gitlab.com/cznic/ccir@v1.0.0/all_test.go (about) 1 // Copyright 2017 The CCIR Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package ccir // import "modernc.org/ccir" 6 7 import ( 8 "bytes" 9 "compress/gzip" 10 "encoding/gob" 11 "encoding/hex" 12 "flag" 13 "fmt" 14 "go/scanner" 15 "go/token" 16 "io/ioutil" 17 "os" 18 "path" 19 "path/filepath" 20 "regexp" 21 "runtime" 22 "runtime/debug" 23 "strings" 24 "testing" 25 "time" 26 27 "modernc.org/cc" 28 "modernc.org/internal/buffer" 29 "modernc.org/ir" 30 "modernc.org/strutil" 31 "modernc.org/virtual" 32 "modernc.org/xc" 33 ) 34 35 func caller(s string, va ...interface{}) { 36 if s == "" { 37 s = strings.Repeat("%v ", len(va)) 38 } 39 _, fn, fl, _ := runtime.Caller(2) 40 fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 41 fmt.Fprintf(os.Stderr, s, va...) 42 fmt.Fprintln(os.Stderr) 43 _, fn, fl, _ = runtime.Caller(1) 44 fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 45 fmt.Fprintln(os.Stderr) 46 os.Stderr.Sync() 47 } 48 49 func dbg(s string, va ...interface{}) { 50 if s == "" { 51 s = strings.Repeat("%v ", len(va)) 52 } 53 _, fn, fl, _ := runtime.Caller(1) 54 fmt.Fprintf(os.Stderr, "# dbg %s:%d ", path.Base(fn), fl) 55 fmt.Fprintf(os.Stderr, s, va...) 56 fmt.Fprintln(os.Stderr) 57 os.Stderr.Sync() 58 } 59 60 func use(...interface{}) {} 61 62 func init() { 63 use(caller, dbg, TODO) //TODOOK 64 isTesting = true 65 flag.BoolVar(&Testing, "testing", false, "") 66 flag.BoolVar(&ir.Testing, "irTesting", false, "") 67 flag.BoolVar(&virtual.Testing, "virtualTesting", false, "") 68 } 69 70 // ============================================================================ 71 72 var ( 73 cpp = flag.Bool("cpp", false, "") 74 errLimit = flag.Int("errlimit", 10, "") 75 filter = flag.String("re", "", "") 76 ndebug = flag.Bool("ndebug", false, "") 77 noexec = flag.Bool("noexec", false, "") 78 oLog = flag.Bool("log", false, "") 79 trace = flag.Bool("trc", false, "") 80 yydebug = flag.Int("yydebug", 0, "") 81 ) 82 83 func errStr(err error) string { 84 switch x := err.(type) { 85 case scanner.ErrorList: 86 if len(x) != 1 { 87 x.RemoveMultiples() 88 } 89 var b bytes.Buffer 90 for i, v := range x { 91 if i != 0 { 92 b.WriteByte('\n') 93 } 94 b.WriteString(v.Error()) 95 if i == 9 { 96 fmt.Fprintf(&b, "\n\t... and %v more errors", len(x)-10) 97 break 98 } 99 } 100 return b.String() 101 default: 102 return err.Error() 103 } 104 } 105 106 func parse(src []string, opts ...cc.Opt) (_ *cc.TranslationUnit, err error) { 107 defer func() { 108 if e := recover(); e != nil && err == nil { 109 err = fmt.Errorf("cc.Parse: PANIC: %v\n%s", e, debug.Stack()) 110 } 111 }() 112 113 model, err := NewModel() 114 if err != nil { 115 return nil, err 116 } 117 118 ast, err := cc.Parse(fmt.Sprintf(` 119 #define __arch__ %s 120 #define __os__ %s 121 #include <builtin.h> 122 123 #define NO_TRAMPOLINES 1 124 `, runtime.GOARCH, runtime.GOOS), 125 src, 126 model, 127 opts..., 128 ) 129 if err != nil { 130 return nil, fmt.Errorf("cc.Parse: %v", errStr(err)) 131 } 132 133 return ast, nil 134 } 135 136 func expect1(wd, match string, hook func(string, string) []string, opts ...cc.Opt) (log buffer.Bytes, exitStatus int, err error) { 137 var lpos token.Position 138 if *cpp { 139 opts = append(opts, cc.Cpp(func(toks []xc.Token) { 140 if len(toks) != 0 { 141 p := toks[0].Position() 142 if p.Filename != lpos.Filename { 143 fmt.Fprintf(&log, "# %d %q\n", p.Line, p.Filename) 144 } 145 lpos = p 146 } 147 for _, v := range toks { 148 log.WriteString(cc.TokSrc(v)) 149 } 150 log.WriteByte('\n') 151 })) 152 } 153 if n := *yydebug; n != 0 { 154 opts = append(opts, cc.YyDebug(n)) 155 } 156 ast, err := parse([]string{CRT0Path, match}, opts...) 157 if err != nil { 158 return log, -1, err 159 } 160 161 objs, err := New(ast) 162 if err != nil { 163 return log, -1, fmt.Errorf("New: %v", err) 164 } 165 166 fmt.Fprintf(&log, "# ccir.New\n") 167 for i, v := range objs { 168 switch x := v.(type) { 169 case *ir.DataDefinition: 170 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value) 171 case *ir.FunctionDefinition: 172 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments) 173 for i, v := range x.Body { 174 fmt.Fprintf(&log, "%#05x\t%v\n", i, v) 175 } 176 default: 177 return log, -1, fmt.Errorf("[%v] %T %v", i, x, x) 178 } 179 } 180 for i, v := range objs { 181 if err := v.Verify(); err != nil { 182 switch x := v.(type) { 183 case *ir.FunctionDefinition: 184 fmt.Fprintf(&log, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments) 185 for i, v := range x.Body { 186 fmt.Fprintf(&log, "%#05x\t%v\n", i, v) 187 } 188 return log, -1, fmt.Errorf("# [%v, err]: Verify (A): %v", i, err) 189 default: 190 return log, -1, fmt.Errorf("[%v, err]: %T %v: %v", i, x, x, err) 191 } 192 } 193 } 194 195 if objs, err = ir.LinkMain(objs); err != nil { 196 return log, -1, fmt.Errorf("ir.LinkMain: %v", err) 197 } 198 199 fmt.Fprintf(&log, "# ir.LinkMain\n") 200 for i, v := range objs { 201 switch x := v.(type) { 202 case *ir.DataDefinition: 203 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value) 204 case *ir.FunctionDefinition: 205 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments) 206 for i, v := range x.Body { 207 fmt.Fprintf(&log, "%#05x\t%v\n", i, v) 208 } 209 default: 210 return log, -1, fmt.Errorf("[%v]: %T %v", i, x, x) 211 } 212 } 213 for i, v := range objs { 214 if err := v.Verify(); err != nil { 215 return log, -1, fmt.Errorf("# [%v, err]: Verify (B): %v", i, err) 216 } 217 } 218 219 bin, err := virtual.LoadMain(objs) 220 if err != nil { 221 return log, -1, fmt.Errorf("virtual.LoadMain: %v", err) 222 } 223 224 var gz bytes.Buffer 225 zw := gzip.NewWriter(&gz) 226 enc := gob.NewEncoder(zw) 227 if err := enc.Encode(bin); err != nil { 228 return log, -1, fmt.Errorf("gob encode: %v", err) 229 } 230 231 if err := zw.Close(); err != nil { 232 return log, -1, fmt.Errorf("gzip close: %v", err) 233 } 234 235 s := virtual.DumpCodeStr(bin.Code, 0, bin.Functions, bin.Lines) 236 fmt.Fprintf(&log, "%s: virtual.LoadMain: code %#05x, text %#05x, data %#05x, bss %#05x, pc2func %v, pc2line %v, gz %v\n%s\n", 237 match, len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(gz.Bytes()), s.Bytes(), 238 ) 239 s.Close() 240 if len(bin.Text) != 0 { 241 fmt.Fprintf(&log, "Text segment\n%s\n", hex.Dump(bin.Text)) 242 } 243 if len(bin.Data) != 0 { 244 fmt.Fprintf(&log, "Data segment\n%s\n", hex.Dump(bin.Data)) 245 } 246 if len(bin.TSRelative) != 0 { 247 fmt.Fprintf(&log, "TS relative bitvector\n%s\n", hex.Dump(bin.TSRelative)) 248 } 249 if len(bin.DSRelative) != 0 { 250 fmt.Fprintf(&log, "DS relative bitvector\n%s\n", hex.Dump(bin.DSRelative)) 251 } 252 253 if *noexec { 254 return log, 0, nil 255 } 256 257 var stdin bytes.Buffer 258 var stdout, stderr buffer.Bytes 259 260 defer func() { 261 stdout.Close() 262 stderr.Close() 263 }() 264 265 if err := func() (err error) { 266 defer func() { 267 if e := recover(); e != nil && err == nil { 268 err = fmt.Errorf("virtual.Exec: PANIC: %v\n%s", e, debug.Stack()) 269 } 270 }() 271 272 vwd, err := ioutil.TempDir("", "ccir-test-") 273 if err != nil { 274 return err 275 } 276 277 if err := os.Chdir(vwd); err != nil { 278 return err 279 } 280 281 defer func() { 282 os.Chdir(wd) 283 os.RemoveAll(vwd) 284 }() 285 286 args := hook(vwd, match) 287 if exitStatus, err = virtual.Exec(bin, args, &stdin, &stdout, &stderr, 1<<20, 1<<20, wd); exitStatus != 0 || err != nil { 288 if b := stdout.Bytes(); b != nil { 289 fmt.Fprintf(&log, "stdout:\n%s\n", b) 290 } 291 if b := stderr.Bytes(); b != nil { 292 fmt.Fprintf(&log, "stderr:\n%s\n", b) 293 } 294 return fmt.Errorf("virtual.Exec: exit status %v, err %v", exitStatus, err) 295 } 296 297 return nil 298 }(); err != nil { 299 return log, exitStatus, err 300 } 301 302 if b := stdout.Bytes(); b != nil { 303 fmt.Fprintf(&log, "stdout:\n%s\n", b) 304 } 305 if b := stderr.Bytes(); b != nil { 306 fmt.Fprintf(&log, "stderr:\n%s\n", b) 307 } 308 309 expect := match[:len(match)-len(filepath.Ext(match))] + ".expect" 310 if _, err := os.Stat(expect); err != nil { 311 if !os.IsNotExist(err) { 312 return log, 0, err 313 } 314 315 return log, 0, nil 316 } 317 318 buf, err := ioutil.ReadFile(expect) 319 if err != nil { 320 return log, 0, err 321 } 322 323 if g, e := stdout.Bytes(), buf; !bytes.Equal(g, e) { 324 return log, 0, fmt.Errorf("==== %v\n==== got\n%s==== exp\n%s", match, g, e) 325 } 326 return log, 0, nil 327 } 328 329 func expect(t *testing.T, dir string, skip func(string) bool, hook func(string, string) []string, opts ...cc.Opt) { 330 wd, err := os.Getwd() 331 if err != nil { 332 t.Fatal(err) 333 } 334 335 matches, err := filepath.Glob(filepath.Join(dir, "*.c")) 336 if err != nil { 337 t.Fatal(err) 338 } 339 340 seq := 0 341 okSeq := 0 342 for _, match := range matches { 343 if skip(match) { 344 continue 345 } 346 347 if *trace { 348 fmt.Println(match) 349 } 350 seq++ 351 doLog := *oLog 352 log, exitStatus, err := expect1(wd, match, hook, opts...) 353 switch { 354 case exitStatus <= 0 && err == nil: 355 okSeq++ 356 default: 357 //dbg("%v\n%v", match, err) 358 if seq-okSeq == 1 { 359 t.Logf("%s: FAIL\n%s\n%s", match, errStr(err), log.Bytes()) 360 doLog = false 361 } 362 } 363 if doLog { 364 t.Logf("%s:\n%s", match, log.Bytes()) 365 } 366 log.Close() 367 } 368 t.Logf("%v/%v ok", okSeq, seq) 369 if okSeq != seq { 370 t.Errorf("failures: %v", seq-okSeq) 371 } 372 } 373 374 func TestTCC(t *testing.T) { 375 wd, err := os.Getwd() 376 if err != nil { 377 t.Fatal(err) 378 } 379 380 testdata, err := filepath.Rel(wd, ccTestdata) 381 if err != nil { 382 t.Fatal(err) 383 } 384 385 var re *regexp.Regexp 386 if s := *filter; s != "" { 387 re = regexp.MustCompile(s) 388 } 389 390 dir := filepath.Join(testdata, filepath.FromSlash("tcc-0.9.26/tests/tests2/")) 391 expect( 392 t, 393 dir, 394 func(match string) bool { 395 if re != nil && !re.MatchString(filepath.Base(match)) { 396 return true 397 } 398 399 return false 400 }, 401 func(wd, match string) []string { 402 switch filepath.Base(match) { 403 case "31_args.c": 404 return []string{"./test", "-", "arg1", "arg2", "arg3", "arg4"} 405 case "46_grep.c": 406 ioutil.WriteFile(filepath.Join(wd, "test"), []byte("abc\ndef\nghi\n"), 0600) 407 return []string{"./grep", "[ea]", "test"} 408 default: 409 return []string{match} 410 } 411 }, 412 cc.AllowCompatibleTypedefRedefinitions(), 413 cc.EnableAnonymousStructFields(), 414 cc.EnableDefineOmitCommaBeforeDDD(), 415 cc.EnableImplicitFuncDef(), 416 cc.ErrLimit(-1), 417 cc.SysIncludePaths([]string{LibcIncludePath}), 418 ) 419 } 420 421 func TestGCCExec(t *testing.T) { 422 blacklist := map[string]struct{}{ 423 // VLA struct field. 424 "20020412-1.c": {}, 425 "20040308-1.c": {}, 426 "align-nest.c": {}, 427 "pr41935.c": {}, 428 429 // Nested function. 430 "20010209-1.c": {}, 431 "20010605-1.c": {}, 432 "20030501-1.c": {}, 433 "20040520-1.c": {}, 434 "20061220-1.c": {}, 435 "20090219-1.c": {}, 436 "920612-2.c": {}, 437 "921017-1.c": {}, 438 "nest-align-1.c": {}, 439 "nest-stdar-1.c": {}, 440 "nestfunc-7.c": {}, 441 "pr22061-3.c": {}, 442 "pr22061-4.c": {}, 443 "pr71494.c": {}, 444 445 // __real__, complex integers and and friends. 446 "20010605-2.c": {}, 447 "20020411-1.c": {}, 448 "20030910-1.c": {}, 449 "20041124-1.c": {}, 450 "20041201-1.c": {}, 451 "20050121-1.c": {}, 452 "complex-1.c": {}, 453 "complex-6.c": {}, 454 "pr38151.c": {}, 455 "pr38969.c": {}, 456 "pr56837.c": {}, 457 458 // Depends on __attribute__((aligned(N))) 459 "20010904-1.c": {}, 460 "20010904-2.c": {}, 461 "align-3.c": {}, 462 "pr23467.c": {}, 463 464 // Depends on __attribute__ ((vector_size (N))) 465 "20050316-1.c": {}, 466 "20050316-2.c": {}, 467 "20050316-3.c": {}, 468 "20050604-1.c": {}, 469 "20050607-1.c": {}, 470 "pr23135.c": {}, 471 "pr53645-2.c": {}, 472 "pr53645.c": {}, 473 "pr60960.c": {}, 474 "pr65427.c": {}, 475 "pr71626-1.c": {}, 476 "pr71626-2.c": {}, 477 "scal-to-vec1.c": {}, 478 "scal-to-vec2.c": {}, 479 "scal-to-vec3.c": {}, 480 "simd-1.c": {}, 481 "simd-2.c": {}, 482 "simd-4.c": {}, 483 "simd-5.c": {}, 484 "simd-6.c": {}, 485 486 // https://goo.gl/XDxJEL 487 "20021127-1.c": {}, 488 489 // asm 490 "20001009-2.c": {}, 491 "20020107-1.c": {}, 492 "20030222-1.c": {}, 493 "20071211-1.c": {}, 494 "20071220-1.c": {}, 495 "20071220-2.c": {}, 496 "960312-1.c": {}, 497 "960830-1.c": {}, 498 "990130-1.c": {}, 499 "990413-2.c": {}, 500 "pr38533.c": {}, 501 "pr40022.c": {}, 502 "pr40657.c": {}, 503 "pr41239.c": {}, 504 "pr43385.c": {}, 505 "pr43560.c": {}, 506 "pr45695.c": {}, 507 "pr46309.c": {}, 508 "pr49279.c": {}, 509 "pr49390.c": {}, 510 "pr51877.c": {}, 511 "pr51933.c": {}, 512 "pr52286.c": {}, 513 "pr56205.c": {}, 514 "pr56866.c": {}, 515 "pr56982.c": {}, 516 "pr57344-1.c": {}, 517 "pr57344-2.c": {}, 518 "pr57344-3.c": {}, 519 "pr57344-4.c": {}, 520 "pr63641.c": {}, 521 "pr65053-1.c": {}, 522 "pr65053-2.c": {}, 523 "pr65648.c": {}, 524 "pr65956.c": {}, 525 "pr68328.c": {}, 526 "pr69320-2.c": {}, 527 "stkalign.c": {}, 528 529 // __label__ 530 "920415-1.c": {}, 531 "920721-4.c": {}, 532 "930406-1.c": {}, 533 "980526-1.c": {}, 534 "pr51447.c": {}, 535 536 // attribute alias 537 "alias-2.c": {}, 538 "alias-3.c": {}, 539 "alias-4.c": {}, 540 541 // _Alignas 542 "pr68532.c": {}, 543 544 // Profiling 545 "eeprof-1.c": {}, 546 547 // 6.5.16/4: The order of evaluation of the operands is unspecified. 548 "pr58943.c": {}, 549 } 550 todolist := map[string]struct{}{ 551 // long double constant out of range for double. 552 "960405-1.c": {}, 553 554 // case range 555 "pr34154.c": {}, 556 557 // VLA. Need to resolve https://gitlab.com/cznic/cc/issues/91 first. 558 "20040411-1.c": {}, 559 "20040423-1.c": {}, 560 "20040811-1.c": {}, 561 "20041218-2.c": {}, 562 "20070919-1.c": {}, 563 "920929-1.c": {}, 564 "970217-1.c": {}, 565 "pr22061-1.c": {}, 566 "pr43220.c": {}, 567 "vla-dealloc-1.c": {}, 568 569 // Initializer 570 "20050613-1.c": {}, // struct B b = { .a.j = 5 }; 571 "20050929-1.c": {}, // struct C e = { &(struct B) { &(struct A) { 1, 2 }, &(struct A) { 3, 4 } }, &(struct A) { 5, 6 } }; 572 "20071029-1.c": {}, // t = (T) { { ++i, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; 573 "921019-1.c": {}, // void *foo[]={(void *)&("X"[0])}; 574 "991228-1.c": {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/991228-1.c:1:51: invalid designator for type double 575 "compndlit-1.c": {}, // x = (struct S) {b:0, a:0, c:({ struct S o = x; o.a == 1 ? 10 : 20;})}; 576 "const-addr-expr-1.c": {}, // int *Upgd_minor_ID = (int *) &((Upgrade_items + 1)->uaattrid); 577 "pr22098-1.c": {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[++a]); 578 "pr22098-2.c": {}, // b = (uintptr_t)(p = &(int []){0, 1, 2}[1]); 579 "pr22098-3.c": {}, // b = (uintptr_t)(p = &(int []){0, f(), 2}[1]); 580 "pr33631.c": {}, // struct { int c; pthread_mutex_t m; } r = { .m = 0 }; 581 "pr70460.c": {}, // static int b[] = { &&lab1 - &&lab0, &&lab2 - &&lab0 }; 582 583 // signal.h 584 "20101011-1.c": {}, 585 586 // &&label expr 587 "comp-goto-1.c": {}, // # [100]: Verify (A): mismatched operand type, got int32, expected uint32; simulator_kernel:0x64: lsh uint32 ; ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/comp-goto-1.c:83:40 588 589 // builtins 590 "pr47237.c": {}, // __builtin_apply, __builtin_apply_args 591 "pr64006.c": {}, // __builtin_mul_overflow 592 "pr68381.c": {}, // __builtin_mul_overflow 593 "pr71554.c": {}, // __builtin_mul_overflow 594 "va-arg-pack-1.c": {}, // __builtin_va_arg_pack 595 596 // long double 597 "pr39228.c": {}, 598 599 // un-flatten (wips wrt cc.0506a942f3efa9b7a0a4b98dbe45bf7e8d06a542) 600 "20030714-1.c": {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/20030714-1.c:102:11: assignment from incompatible type ('unsigned' = '<undefined>') 601 "anon-1.c": {}, // cc.Parse: ../cc/testdata/gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/anon-1.c:22:7: struct{int; ;} has no member named b 602 603 //TODO 604 "zero-struct-1.c": {}, // New: ccir.New: PANIC: 2 605 } 606 607 wd, err := os.Getwd() 608 if err != nil { 609 t.Fatal(err) 610 } 611 612 testdata, err := filepath.Rel(wd, ccTestdata) 613 if err != nil { 614 t.Fatal(err) 615 } 616 617 var re *regexp.Regexp 618 if s := *filter; s != "" { 619 re = regexp.MustCompile(s) 620 } 621 622 dir := filepath.Join(testdata, filepath.FromSlash("gcc-6.3.0/gcc/testsuite/gcc.c-torture/execute/")) 623 expect( 624 t, 625 dir, 626 func(match string) bool { 627 base := filepath.Base(match) 628 _, skip := blacklist[base] 629 if _, skip2 := todolist[base]; skip2 { 630 skip = true 631 } 632 if re != nil { 633 skip = !re.MatchString(base) 634 } 635 return skip 636 }, 637 func(wd, match string) []string { 638 return []string{match} 639 }, 640 cc.AllowCompatibleTypedefRedefinitions(), 641 cc.EnableAlignOf(), 642 cc.EnableAlternateKeywords(), 643 cc.EnableAnonymousStructFields(), 644 cc.EnableAsm(), 645 cc.EnableBuiltinClassifyType(), 646 cc.EnableBuiltinConstantP(), 647 cc.EnableComputedGotos(), 648 cc.EnableDefineOmitCommaBeforeDDD(), 649 cc.EnableEmptyDeclarations(), 650 cc.EnableEmptyStructs(), 651 cc.EnableImaginarySuffix(), 652 cc.EnableImplicitFuncDef(), 653 cc.EnableImplicitIntType(), 654 cc.EnableLegacyDesignators(), 655 cc.EnableNonConstStaticInitExpressions(), 656 cc.EnableOmitConditionalOperand(), 657 cc.EnableOmitFuncArgTypes(), 658 cc.EnableOmitFuncRetType(), 659 cc.EnableParenthesizedCompoundStatemen(), 660 cc.EnableTypeOf(), 661 cc.EnableUnsignedEnums(), 662 cc.EnableWideBitFieldTypes(), 663 cc.ErrLimit(-1), 664 cc.SysIncludePaths([]string{LibcIncludePath}), 665 ) 666 } 667 668 type file struct { 669 name string 670 data []byte 671 } 672 673 func (f file) String() string { return fmt.Sprintf("%v %v", len(f.data), f.name) } 674 675 func exec(t *testing.T, bin *virtual.Binary, argv []string, inputFiles []file) (output []byte, resultFiles []file, duration time.Duration) { 676 dir, err := ioutil.TempDir("", "ccir-test-") 677 if err != nil { 678 t.Fatal(err) 679 } 680 681 defer os.RemoveAll(dir) 682 683 cwd, err := os.Getwd() 684 if err != nil { 685 t.Fatal(err) 686 } 687 688 defer os.Chdir(cwd) 689 690 if err := os.Chdir(dir); err != nil { 691 t.Fatal(err) 692 } 693 694 for _, v := range inputFiles { 695 if err := ioutil.WriteFile(v.name, v.data, 0600); err != nil { 696 t.Fatal(err) 697 } 698 } 699 700 defer func() { 701 if e := recover(); e != nil && err == nil { 702 t.Fatal(fmt.Errorf("virtual.Exec: PANIC: %v\n%s", e, debug.Stack())) 703 } 704 }() 705 706 var stdin, stdout, stderr bytes.Buffer 707 t0 := time.Now() 708 exitStatus, err := virtual.Exec(bin, argv, &stdin, &stdout, &stderr, 1<<25, 1<<20, cwd) 709 duration = time.Since(t0) 710 if err != nil { 711 var log bytes.Buffer 712 if b := stdout.Bytes(); b != nil { 713 fmt.Fprintf(&log, "stdout:\n%s\n", b) 714 } 715 if b := stderr.Bytes(); b != nil { 716 fmt.Fprintf(&log, "stderr:\n%s\n", b) 717 } 718 t.Fatalf("exit status %v, err %v\n%s", exitStatus, err, log.Bytes()) 719 } 720 721 glob, err := filepath.Glob("*") 722 if err != nil { 723 t.Fatal(err) 724 } 725 726 for _, m := range glob { 727 data, err := ioutil.ReadFile(m) 728 if err != nil { 729 t.Fatal(err) 730 } 731 732 resultFiles = append(resultFiles, file{m, data}) 733 } 734 735 return bytes.TrimSpace(append(stdout.Bytes(), stderr.Bytes()...)), resultFiles, duration 736 } 737 738 func build(t *testing.T, predef string, tus [][]string, opts ...cc.Opt) *virtual.Binary { 739 var log buffer.Bytes 740 var lpos token.Position 741 if *cpp { 742 opts = append(opts, cc.Cpp(func(toks []xc.Token) { 743 if len(toks) != 0 { 744 p := toks[0].Position() 745 if p.Filename != lpos.Filename { 746 fmt.Fprintf(&log, "# %d %q\n", p.Line, p.Filename) 747 } 748 lpos = p 749 } 750 for _, v := range toks { 751 log.WriteString(cc.TokSrc(v)) 752 } 753 log.WriteByte('\n') 754 })) 755 } 756 757 ndbg := "" 758 if *ndebug { 759 ndbg = "#define NDEBUG 1" //TODOOK 760 } 761 var build [][]ir.Object 762 tus = append(tus, []string{CRT0Path}) 763 for _, src := range tus { 764 model, err := NewModel() 765 if err != nil { 766 t.Fatal(err) 767 } 768 769 ast, err := cc.Parse( 770 fmt.Sprintf(` 771 %s 772 #define __arch__ %s 773 #define __os__ %s 774 #include <builtin.h> 775 %s 776 `, ndbg, runtime.GOARCH, runtime.GOOS, predef), 777 src, 778 model, 779 append([]cc.Opt{ 780 cc.AllowCompatibleTypedefRedefinitions(), 781 cc.EnableImplicitFuncDef(), 782 cc.EnableNonConstStaticInitExpressions(), 783 cc.ErrLimit(*errLimit), 784 cc.SysIncludePaths([]string{LibcIncludePath}), 785 }, opts...)..., 786 ) 787 if s := log.Bytes(); len(s) != 0 { 788 t.Logf("\n%s", s) 789 log.Close() 790 } 791 if err != nil { 792 t.Fatal(errStr(err)) 793 } 794 795 objs, err := New(ast) 796 if err != nil { 797 t.Fatal(err) 798 } 799 800 if *oLog { 801 for i, v := range objs { 802 switch x := v.(type) { 803 case *ir.DataDefinition: 804 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Value) 805 case *ir.FunctionDefinition: 806 fmt.Fprintf(&log, "# [%v]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments) 807 for i, v := range x.Body { 808 fmt.Fprintf(&log, "%#05x\t%v\n", i, v) 809 } 810 default: 811 t.Fatalf("[%v]: %T %v: %v", i, x, x, err) 812 } 813 } 814 } 815 for i, v := range objs { 816 if err := v.Verify(); err != nil { 817 switch x := v.(type) { 818 case *ir.FunctionDefinition: 819 fmt.Fprintf(&log, "# [%v, err]: %T %v %v\n", i, x, x.ObjectBase, x.Arguments) 820 for i, v := range x.Body { 821 fmt.Fprintf(&log, "%#05x\t%v\n", i, v) 822 } 823 t.Fatalf("# [%v]: Verify (A): %v\n%s", i, err, log.Bytes()) 824 default: 825 t.Fatalf("[%v]: %T %v: %v", i, x, x, err) 826 } 827 } 828 } 829 build = append(build, objs) 830 } 831 832 linked, err := ir.LinkMain(build...) 833 if err != nil { 834 t.Fatalf("ir.LinkMain: %s\n%s", err, log.Bytes()) 835 } 836 837 for _, v := range linked { 838 if err := v.Verify(); err != nil { 839 t.Fatal(err) 840 } 841 } 842 843 bin, err := virtual.LoadMain(linked) 844 if err != nil { 845 t.Fatal(err) 846 } 847 848 return bin 849 } 850 851 func findRepo(t *testing.T, s string) string { 852 s = filepath.FromSlash(s) 853 for _, v := range strings.Split(strutil.Gopath(), string(os.PathListSeparator)) { 854 p := filepath.Join(v, "src", s) 855 fi, err := os.Lstat(p) 856 if err != nil { 857 continue 858 } 859 860 if fi.IsDir() { 861 wd, err := os.Getwd() 862 if err != nil { 863 t.Fatal(err) 864 } 865 866 if p, err = filepath.Rel(wd, p); err != nil { 867 t.Fatal(err) 868 } 869 870 return p 871 } 872 } 873 return "" 874 } 875 876 func TestSelfie(t *testing.T) { 877 const repo = "github.com/cksystemsteaching/selfie" 878 pth := findRepo(t, repo) 879 if pth == "" { 880 t.Logf("repository not found, skipping: %v", repo) 881 return 882 } 883 884 bin := build(t, "", [][]string{{filepath.Join(pth, "selfie.c")}}) 885 if m, _ := NewModel(); m.Items[cc.Ptr].Size != 4 { 886 return 887 } 888 889 args := []string{"./selfie"} 890 out, _, d := exec(t, bin, args, nil) 891 if g, e := out, []byte("./selfie: usage: selfie { -c { source } | -o binary | -s assembly | -l binary } [ ( -m | -d | -y | -min | -mob ) size ... ]"); !bytes.Equal(g, e) { 892 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 893 } 894 895 t.Logf("%s\n%s\n%v", args, out, d) 896 897 args = []string{"./selfie", "-c", "hello.c", "-m", "1"} 898 out, _, d = exec(t, bin, args, []file{{"hello.c", []byte(` 899 int *foo; 900 901 int main() { 902 foo = "Hello world!"; 903 while (*foo!=0) { 904 write(1, foo, 4); 905 foo = foo + 1; 906 } 907 *foo = 10; 908 write(1, foo, 1); 909 } 910 `)}}) 911 if g, e := out, []byte(`./selfie: this is selfie's starc compiling hello.c 912 ./selfie: 141 characters read in 12 lines and 0 comments 913 ./selfie: with 102(72.46%) characters in 52 actual symbols 914 ./selfie: 1 global variables, 1 procedures, 1 string literals 915 ./selfie: 2 calls, 3 assignments, 1 while, 0 if, 0 return 916 ./selfie: 660 bytes generated with 159 instructions and 24 bytes of data 917 ./selfie: this is selfie's mipster executing hello.c with 1MB of physical memory 918 Hello world! 919 hello.c: exiting with exit code 0 and 0.00MB of mallocated memory 920 ./selfie: this is selfie's mipster terminating hello.c with exit code 0 and 0.01MB of mapped memory 921 ./selfie: profile: total,max(ratio%)@addr(line#),2max(ratio%)@addr(line#),3max(ratio%)@addr(line#) 922 ./selfie: calls: 5,4(80.00%)@0x88(~1),1(20.00%)@0x17C(~5),0(0.00%) 923 ./selfie: loops: 3,3(100.00%)@0x198(~6),0(0.00%),0(0.00%) 924 ./selfie: loads: 32,4(12.50%)@0x88(~1),3(9.38%)@0x1D4(~7),1(3.12%)@0x24(~1) 925 ./selfie: stores: 20,3(15.01%)@0x1D0(~7),1(5.00%)@0x4C(~1),0(0.00%)`); !bytes.Equal(g, e) { 926 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 927 } 928 929 t.Logf("%s\n%s\n%v", args, out, d) 930 931 selfie, err := ioutil.ReadFile(filepath.Join(pth, "selfie.c")) 932 if err != nil { 933 t.Fatal(err) 934 } 935 936 args = []string{"./selfie", "-c", "selfie.c"} 937 out, _, d = exec(t, bin, args, []file{{"selfie.c", selfie}}) 938 if g, e := out, []byte(`./selfie: this is selfie's starc compiling selfie.c 939 ./selfie: 176362 characters read in 7086 lines and 970 comments 940 ./selfie: with 97764(55.55%) characters in 28916 actual symbols 941 ./selfie: 260 global variables, 290 procedures, 450 string literals 942 ./selfie: 1960 calls, 722 assignments, 57 while, 571 if, 241 return 943 ./selfie: 121676 bytes generated with 28783 instructions and 6544 bytes of data`); !bytes.Equal(g, e) { 944 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 945 } 946 947 t.Logf("%s\n%s\n%v", args, out, d) 948 } 949 950 func TestC4(t *testing.T) { 951 bin := build(t, "", [][]string{{"testdata/github.com/rswier/c4/c4.c"}}) 952 953 args := []string{"./c4"} 954 out, _, d := exec(t, bin, args, nil) 955 if g, e := out, []byte("usage: c4 [-s] [-d] file ..."); !bytes.Equal(g, e) { 956 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 957 } 958 959 t.Logf("%s\n%s\n%v", args, out, d) 960 961 hello, err := ioutil.ReadFile("testdata/github.com/rswier/c4/hello.c") 962 if err != nil { 963 t.Fatal(err) 964 } 965 966 args = []string{"./c4", "hello.c"} 967 out, _, d = exec(t, bin, args, []file{{"hello.c", hello}}) 968 if g, e := out, []byte(`hello, world 969 exit(0) cycle = 9`); !bytes.Equal(g, e) { 970 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 971 } 972 973 t.Logf("%s\n%s\n%v", args, out, d) 974 975 args = []string{"./c4", "-s", "hello.c"} 976 out, _, d = exec(t, bin, args, []file{{"hello.c", hello}}) 977 t.Logf("%s\n%s\n%v", args, out, d) 978 979 c4, err := ioutil.ReadFile("testdata/github.com/rswier/c4/c4.c") 980 if err != nil { 981 t.Fatal(err) 982 } 983 984 args = []string{"./c4", "c4.c", "hello.c"} 985 out, _, d = exec(t, bin, args, []file{{"c4.c", c4}, {"hello.c", hello}}) 986 if g, e := out, []byte(`hello, world 987 exit(0) cycle = 9 988 exit(0) cycle = 25604`); !bytes.Equal(g, e) { 989 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 990 } 991 992 t.Logf("%s\n%s\n%v", args, out, d) 993 } 994 995 func TestSQLite(t *testing.T) { 996 const repo = "sqlite.org/sqlite-amalgamation-3190300/" 997 pth := findRepo(t, repo) 998 if pth == "" { 999 t.Logf("repository not found, skipping: %v", repo) 1000 return 1001 } 1002 1003 bin := build( 1004 t, 1005 `#define SQLITE_DEBUG 1 //TODOOK 1006 #define SQLITE_ENABLE_MEMSYS5 1`, 1007 [][]string{ 1008 {"testdata/sqlite/test.c"}, 1009 {filepath.Join(pth, "sqlite3.c")}, 1010 }, 1011 cc.EnableAnonymousStructFields(), 1012 cc.EnableWideBitFieldTypes(), 1013 cc.IncludePaths([]string{pth}), 1014 ) 1015 var gz bytes.Buffer 1016 zw := gzip.NewWriter(&gz) 1017 enc := gob.NewEncoder(zw) 1018 if err := enc.Encode(bin); err != nil { 1019 t.Fatal(err) 1020 } 1021 1022 if err := zw.Close(); err != nil { 1023 t.Fatal(err) 1024 } 1025 1026 t.Logf("code %#08x, text %#08x, data %#08x, bss %#08x, pc2func %v, pc2line %v, gz %v\n", 1027 len(bin.Code), len(bin.Text), len(bin.Data), bin.BSS, len(bin.Functions), len(bin.Lines), len(gz.Bytes()), 1028 ) 1029 1030 args := []string{"./test"} 1031 out, f, d := exec(t, bin, args, nil) 1032 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1033 if g, e := out, []byte("Usage: ./test DATABASE SQL-STATEMENT"); !bytes.Equal(g, e) { 1034 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1035 } 1036 1037 args = []string{"./test", "foo"} 1038 out, f, d = exec(t, bin, args, nil) 1039 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1040 if g, e := out, []byte("Usage: ./test DATABASE SQL-STATEMENT"); !bytes.Equal(g, e) { 1041 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1042 } 1043 1044 args = []string{"./test", "foo", "bar"} 1045 out, f, d = exec(t, bin, args, nil) 1046 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1047 if g, e := out, []byte(`FAIL (1) near "bar": syntax error 1048 SQL error: near "bar": syntax error`); !bytes.Equal(g, e) { 1049 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1050 } 1051 1052 args = []string{"./test", "foo", "select * from t"} 1053 out, f, d = exec(t, bin, args, nil) 1054 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1055 if g, e := out, []byte(`FAIL (1) no such table: t 1056 SQL error: no such table: t`); !bytes.Equal(g, e) { 1057 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1058 } 1059 1060 args = []string{"./test", "foo", "select name from sqlite_master where type='table'"} 1061 out, f, d = exec(t, bin, args, nil) 1062 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1063 if g, e := out, []byte(""); !bytes.Equal(g, e) { 1064 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1065 } 1066 1067 args = []string{"./test", "foo", "create table t(i int)"} 1068 out, f, d = exec(t, bin, args, nil) 1069 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1070 if g, e := out, []byte(""); !bytes.Equal(g, e) { 1071 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1072 } 1073 1074 args = []string{"./test", "foo", ` 1075 create table t(i int); 1076 select name from sqlite_master where type='table'; 1077 `} 1078 out, f, d = exec(t, bin, args, nil) 1079 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1080 if g, e := out, []byte("name = t"); !bytes.Equal(g, e) { 1081 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1082 } 1083 1084 args = []string{"./test", "foo", ` 1085 create table t(i int); 1086 select name from sqlite_master where type='table'; 1087 insert into t values(42), (314); 1088 select * from t order by i asc; 1089 select * from t order by i desc; 1090 `} 1091 out, f, d = exec(t, bin, args, nil) 1092 t.Logf("%q\n%s\n%v\n%v", args, out, d, f) 1093 if g, e := out, []byte(`name = t 1094 i = 42 1095 i = 314 1096 i = 314 1097 i = 42`); !bytes.Equal(g, e) { 1098 t.Fatalf("\ngot\n%s\nexp\n%s", g, e) 1099 } 1100 } 1101 1102 func TestOther(t *testing.T) { 1103 var re *regexp.Regexp 1104 if s := *filter; s != "" { 1105 re = regexp.MustCompile(s) 1106 } 1107 1108 expect( 1109 t, 1110 "testdata", 1111 func(match string) bool { 1112 if re != nil && !re.MatchString(filepath.Base(match)) { 1113 return true 1114 } 1115 1116 return false 1117 }, 1118 func(wd, match string) []string { 1119 return []string{match} 1120 }, 1121 cc.EnableImplicitFuncDef(), 1122 cc.ErrLimit(-1), 1123 cc.SysIncludePaths([]string{LibcIncludePath}), 1124 cc.AllowCompatibleTypedefRedefinitions(), 1125 ) 1126 }