modernc.org/ccgo/v3@v3.16.14/lib/all_test.go (about) 1 // Copyright 2020 The CCGO 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 ccgo // import "modernc.org/ccgo/v3/lib" 6 7 import ( 8 "bufio" 9 "bytes" 10 "context" 11 "encoding/hex" 12 "flag" 13 "fmt" 14 "io" 15 "io/ioutil" 16 "os" 17 "os/exec" 18 "path" 19 "path/filepath" 20 "reflect" 21 "regexp" 22 "runtime" 23 "runtime/debug" 24 "sort" 25 "strconv" 26 "strings" 27 "sync" 28 "sync/atomic" 29 "testing" 30 "time" 31 "unsafe" 32 33 "github.com/dustin/go-humanize" 34 "github.com/pmezard/go-difflib/difflib" 35 "modernc.org/cc/v3" 36 "modernc.org/ccorpus" 37 ) 38 39 func caller(s string, va ...interface{}) { 40 if s == "" { 41 s = strings.Repeat("%v ", len(va)) 42 } 43 _, fn, fl, _ := runtime.Caller(2) 44 fmt.Fprintf(os.Stderr, "# caller: %s:%d: ", path.Base(fn), fl) 45 fmt.Fprintf(os.Stderr, s, va...) 46 fmt.Fprintln(os.Stderr) 47 _, fn, fl, _ = runtime.Caller(1) 48 fmt.Fprintf(os.Stderr, "# \tcallee: %s:%d: ", path.Base(fn), fl) 49 fmt.Fprintln(os.Stderr) 50 os.Stderr.Sync() 51 } 52 53 func dbg(s string, va ...interface{}) { 54 if s == "" { 55 s = strings.Repeat("%v ", len(va)) 56 } 57 _, fn, fl, _ := runtime.Caller(1) 58 fmt.Fprintf(os.Stderr, "# dbg %s:%d: ", path.Base(fn), fl) 59 fmt.Fprintf(os.Stderr, s, va...) 60 fmt.Fprintln(os.Stderr) 61 os.Stderr.Sync() 62 } 63 64 func TODO(...interface{}) string { //TODOOK 65 _, fn, fl, _ := runtime.Caller(1) 66 return fmt.Sprintf("# TODO: %s:%d:\n", path.Base(fn), fl) //TODOOK 67 } 68 69 func stack() string { return string(debug.Stack()) } 70 71 func use(...interface{}) {} 72 73 func init() { 74 use(caller, dbg, TODO, stack) //TODOOK 75 } 76 77 // ---------------------------------------------------------------------------- 78 79 const execTimeout = time.Minute * 30 80 81 var ( 82 fs = ccorpus.FileSystem() 83 84 oBlackBox = flag.String("blackbox", "", "Record CSmith file to this file") 85 oCSmith = flag.Duration("csmith", 15*time.Minute, "") 86 oCpp = flag.Bool("cpp", false, "Amend compiler errors with preprocessor output") 87 oDebug = flag.Bool("debug", false, "") 88 oFullPaths = flag.Bool("full-paths", false, "") 89 oGCC = flag.String("gcc", "", "") 90 oKeep = flag.Bool("keep", false, "keep temp directories") 91 oKeepTmp = flag.Bool("keep-tmp", false, "") 92 oO = flag.Int("O", 1, "") 93 oRE = flag.String("re", "", "") 94 oStackTrace = flag.Bool("trcstack", false, "") 95 oTrace = flag.Bool("trc", false, "Print tested paths.") 96 oTraceF = flag.Bool("trcf", false, "Print test file content") 97 oTraceO = flag.Bool("trco", false, "Print test output") 98 oTrc2 = flag.Bool("trc2", false, "") 99 oXTags = flag.String("xtags", "", "passed to go build of TestSQLite") 100 writeFailed = flag.Bool("write-failed", false, "Write all failed tests into a file called FAILED in the cwd, in the format of go maps for easy copy-pasting.") 101 102 gccDir = filepath.FromSlash("testdata/gcc-9.1.0") 103 sqliteDir = filepath.FromSlash("testdata/sqlite-amalgamation-3420000") 104 tccDir = filepath.FromSlash("testdata/tcc-0.9.27") 105 106 overlayDir string 107 re *regexp.Regexp 108 systemCC string 109 systemCCVersion string 110 tempDir string 111 testWD string 112 initIncludePathsOnce sync.Once 113 includePaths []string 114 predefined string 115 sysIncludePaths []string 116 117 keep = map[string]struct{}{ 118 "go.mod": {}, 119 "go.sum": {}, 120 } 121 122 csmithDefaultArgs = strings.Join([]string{ 123 "--bitfields", // --bitfields | --no-bitfields: enable | disable full-bitfields structs (disabled by default). 124 "--max-nested-struct-level", "10", // --max-nested-struct-level <num>: limit maximum nested level of structs to <num>(default 0). Only works in the exhaustive mode. 125 "--no-const-pointers", // --const-pointers | --no-const-pointers: enable | disable const pointers (enabled by default). 126 "--no-consts", // --consts | --no-consts: enable | disable const qualifier (enabled by default). 127 "--no-packed-struct", // --packed-struct | --no-packed-struct: enable | disable packed structs by adding #pragma pack(1) before struct definition (disabled by default). 128 "--no-volatile-pointers", // --volatile-pointers | --no-volatile-pointers: enable | disable volatile pointers (enabled by default). 129 "--no-volatiles", // --volatiles | --no-volatiles: enable | disable volatiles (enabled by default). 130 "--paranoid", // --paranoid | --no-paranoid: enable | disable pointer-related assertions (disabled by default). 131 }, " ") 132 ) 133 134 func TestMain(m *testing.M) { 135 var rc int 136 defer func() { 137 if err := recover(); err != nil { 138 rc = 1 139 fmt.Fprintf(os.Stderr, "PANIC: %v\n%s\n", err, debug.Stack()) 140 } 141 os.Exit(rc) 142 }() 143 144 // fmt.Printf("test binary compiled for %s/%s\n", runtime.GOOS, runtime.GOARCH) 145 // fmt.Printf("temp dir: %s\n", os.TempDir()) //TODO- 146 // if s := os.Getenv("CCGO_CPP"); s != "" { 147 // fmt.Printf("CCGO_CPP=%s\n", os.Getenv("CCGO_CPP")) 148 // } 149 150 flag.BoolVar(&oTraceW, "trcw", false, "Print generator writes") 151 flag.BoolVar(&oTraceG, "trcg", false, "Print generator output") 152 flag.BoolVar(&oTracePin, "trcpin", false, "Print pinning") 153 flag.Parse() 154 if s := *oRE; s != "" { 155 re = regexp.MustCompile(s) 156 } 157 var err error 158 if testWD, err = os.Getwd(); err != nil { 159 panic("Cannot determine working dir: " + err.Error()) 160 } 161 s := filepath.FromSlash("testdata/overlay") 162 if overlayDir, err = filepath.Abs(s); err != nil { 163 panic(err) //TODOOK 164 } 165 if *oGCC == "" { 166 var err error 167 initIncludePathsOnce.Do(func() { err = initIncludePaths("") }) 168 if err != nil { 169 fmt.Println(err) 170 os.Exit(1) 171 } 172 173 if systemCC, err = exec.LookPath(env("CC", "gcc")); err != nil { 174 fmt.Println(err) 175 os.Exit(1) 176 } 177 178 fmt.Fprintf(os.Stderr, "CC=%s\n", systemCC) 179 out, err := exec.Command(systemCC, "--version").CombinedOutput() 180 if err == nil { 181 if a := strings.Split(string(out), "\n"); len(a) > 0 { 182 systemCCVersion = a[0] 183 fmt.Fprintf(os.Stderr, "%s\n", systemCCVersion) 184 } 185 } 186 187 os.Exit(testMain(m)) 188 } 189 190 var args []string 191 for i, v := range os.Args { 192 if v == "-gcc" { 193 args = append(os.Args[:i], os.Args[i+2:]...) 194 } 195 } 196 a := strings.Split(*oGCC, ",") 197 for _, suffix := range a { 198 systemCC = fmt.Sprintf("gcc-%s", suffix) 199 systemCPP := fmt.Sprintf("cpp-%s", suffix) 200 var err error 201 if systemCC, err = exec.LookPath(systemCC); err != nil { 202 fmt.Fprintf(os.Stderr, "%s: %s\n", systemCC, err) 203 continue 204 } 205 206 if systemCPP, err = exec.LookPath(systemCPP); err != nil { 207 fmt.Fprintf(os.Stderr, "%s: %s\n", systemCPP, err) 208 continue 209 } 210 211 os.Setenv("CC", systemCC) 212 os.Setenv("CCGO_CPP", systemCPP) 213 cmd := exec.Command(args[0], args[1:]...) 214 cmd.Stdout = os.Stdout 215 cmd.Stderr = os.Stderr 216 if err := cmd.Run(); err != nil { 217 rc = 1 218 } 219 } 220 os.Exit(rc) 221 } 222 223 func initGoMod() error { 224 switch os.Getenv("GO111MODULE") { 225 case "off": 226 return nil 227 } 228 229 dummy := filepath.Join(tempDir, "dummy.go") 230 if err := ioutil.WriteFile(dummy, []byte(` 231 package main 232 233 import ( 234 "modernc.org/libc" 235 ) 236 237 var ( 238 _ libc.TLS 239 ) 240 func main() {} 241 `), 0600); err != nil { 242 return err 243 } 244 245 wd, err := os.Getwd() 246 if err != nil { 247 return err 248 } 249 250 defer os.Chdir(wd) 251 252 if err := os.Chdir(tempDir); err != nil { 253 return err 254 } 255 256 if b, err := exec.Command("go", "mod", "init", "example.com/ccgotest").CombinedOutput(); err != nil { 257 return fmt.Errorf("go mod init: %s\nFAIL: %v", b, err) 258 } 259 260 if b, err := exec.Command("go", "mod", "tidy").CombinedOutput(); err != nil { 261 return fmt.Errorf("go mod tidy: %s\nFAIL: %v", b, err) 262 } 263 264 return nil 265 } 266 267 func testMain(m *testing.M) int { 268 var err error 269 tempDir, err = ioutil.TempDir("", "ccgo-test-") 270 if err != nil { 271 panic(err) //TODOOK 272 } 273 274 if err = initGoMod(); err != nil { 275 panic(err) //TODOOK 276 } 277 278 switch { 279 case *oKeepTmp: 280 fmt.Fprintf(os.Stderr, "keeping temporary directory %s\n", tempDir) 281 default: 282 defer os.RemoveAll(tempDir) 283 } 284 285 s := filepath.FromSlash("testdata/overlay") 286 if overlayDir, err = filepath.Abs(s); err != nil { 287 panic(err) //TODOOK 288 } 289 290 return m.Run() 291 } 292 293 func initIncludePaths(cpp string) error { 294 var err error 295 predefined, includePaths, sysIncludePaths, err = cc.HostConfig(cpp) 296 if err != nil { 297 return err 298 } 299 300 includePaths = append(includePaths, "@") 301 includePaths = append(includePaths, sysIncludePaths...) 302 return nil 303 } 304 305 type golden struct { 306 t *testing.T 307 f *os.File 308 w *bufio.Writer 309 } 310 311 func newGolden(t *testing.T, fn string) *golden { 312 if *oRE != "" { 313 return &golden{w: bufio.NewWriter(ioutil.Discard)} 314 } 315 316 f, err := os.Create(filepath.FromSlash(fn)) 317 if err != nil { // Possibly R/O fs in a VM 318 base := filepath.Base(filepath.FromSlash(fn)) 319 f, err = ioutil.TempFile("", base) 320 if err != nil { 321 t.Fatal(err) 322 } 323 324 t.Logf("writing results to %s\n", f.Name()) 325 } 326 327 w := bufio.NewWriter(f) 328 return &golden{t, f, w} 329 } 330 331 func (g *golden) close() { 332 if g.f == nil { 333 return 334 } 335 336 if err := g.w.Flush(); err != nil { 337 g.t.Fatal(err) 338 } 339 340 if err := g.f.Close(); err != nil { 341 g.t.Fatal(err) 342 } 343 } 344 345 func h(v interface{}) string { 346 switch x := v.(type) { 347 case int: 348 return humanize.Comma(int64(x)) 349 case int64: 350 return humanize.Comma(x) 351 case uint64: 352 return humanize.Comma(int64(x)) 353 case float64: 354 return humanize.CommafWithDigits(x, 0) 355 default: 356 panic(fmt.Errorf("%T", x)) //TODOOK 357 } 358 } 359 360 type runResult struct { 361 ccTime time.Duration 362 csmithSrc []byte 363 ccgoTime time.Duration 364 err error 365 name string 366 out []byte 367 } 368 369 type skipErr string 370 371 func (e skipErr) Error() string { return "skipped: " + string(e) } 372 373 type runTask struct { 374 args []string 375 c chan *runResult 376 cmd string 377 csmithSrc []byte 378 opts []string 379 src string 380 381 ccCanFail bool 382 doNotExec bool 383 hasBinaryOutput bool 384 } 385 386 func (t *runTask) run() { 387 r := &runResult{name: t.src} 388 r.out, r.err, r.ccTime, r.ccgoTime = t.run0() 389 t.c <- r 390 } 391 392 func (t *runTask) run0() (_ []byte, err error, ccTime, ccgoTime time.Duration) { 393 const outLimit = 1 << 16 394 defer func() { 395 if e := recover(); e != nil { 396 switch { 397 case err == nil: 398 err = fmt.Errorf("PANIC: %v\n%s", e, debug.Stack()) 399 default: 400 err = fmt.Errorf("%v\nPANIC: %v\n%s", err, e, debug.Stack()) 401 } 402 } 403 }() 404 405 overlay := filepath.Join(overlayDir, t.src) 406 b, err := ioutil.ReadFile(overlay) 407 if err != nil { 408 if !os.IsNotExist(err) { 409 return nil, err, ccTime, ccgoTime 410 } 411 412 f, err := fs.Open(t.src) 413 if err != nil { 414 return nil, err, ccTime, ccgoTime 415 } 416 417 if b, err = ioutil.ReadAll(f); err != nil { 418 return nil, err, ccTime, ccgoTime 419 } 420 421 if err = f.Close(); err != nil { 422 return nil, err, ccTime, ccgoTime 423 } 424 } 425 426 overlay = filepath.Join(overlayDir, t.src+".expectrc") 427 b2, err := ioutil.ReadFile(overlay) 428 if err != nil { 429 f, err := fs.Open(t.src + ".expectrc") 430 if err == nil { 431 if b2, err = ioutil.ReadAll(f); err != nil { 432 return nil, err, ccTime, ccgoTime 433 } 434 435 if err = f.Close(); err != nil { 436 return nil, err, ccTime, ccgoTime 437 } 438 } 439 } 440 var expectRC int 441 if len(b2) != 0 { 442 s := strings.TrimSpace(string(b2)) 443 n, err := strconv.ParseUint(s, 10, 32) 444 if err != nil { 445 return nil, err, ccTime, ccgoTime 446 } 447 448 expectRC = int(n) 449 } 450 451 baseName := filepath.Base(t.src) 452 if err := ioutil.WriteFile(baseName, b, 0600); err != nil { 453 return nil, err, ccTime, ccgoTime 454 } 455 456 args, err := getArgs(t.src) 457 if err != nil { 458 return nil, err, ccTime, ccgoTime 459 } 460 461 ccArgs := append([]string{"-w", "-lm"}, t.opts...) 462 ok := true 463 for _, v := range t.opts { 464 if strings.HasPrefix(v, "-O") { 465 ok = false 466 break 467 } 468 } 469 if ok && runtime.GOOS != "darwin" { 470 if o := *oO; o >= 0 { 471 ccArgs = append(ccArgs, fmt.Sprintf("-O%d", o)) 472 } 473 } 474 if t.doNotExec { 475 ccArgs = append(ccArgs, "-c") 476 } 477 binary, err := makeCCBinary(baseName, t.doNotExec, ccArgs...) 478 if err != nil { 479 return nil, skipErr(err.Error()), ccTime, ccgoTime 480 } 481 482 const ( 483 ccOut = "cc.out" 484 ccgoOut = "ccgo.out" 485 ) 486 var binaryBytes, binaryBytes2 int 487 var expected []byte 488 if !t.doNotExec { 489 ctx, cancel := context.WithTimeout(context.Background(), execTimeout) 490 defer cancel() 491 if t.cmd != "" { 492 binary = t.cmd 493 } 494 if len(t.args) != 0 { 495 args = t.args 496 } 497 t0 := time.Now() 498 if *oTrc2 { 499 fmt.Fprintf(os.Stderr, "%v: started CC binary for %s: %v %v\n", t0, baseName, binary, args) 500 } 501 switch { 502 case t.hasBinaryOutput: 503 binaryBytes, err = execute(ctx, binary, ccOut, args) 504 defer os.Remove(ccOut) 505 default: 506 if expected, err = testSingleCombinedoutput(ctx, exec.CommandContext(ctx, binary, args...)); len(expected) > outLimit { 507 panic(todo("", t.src, len(expected))) 508 } 509 } 510 ccTime = time.Since(t0) 511 if *oTrc2 { 512 switch { 513 case t.hasBinaryOutput: 514 fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes, err) 515 default: 516 fmt.Fprintf(os.Stderr, "%v: CC binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, expected) 517 } 518 } 519 if err != nil { 520 switch { 521 case t.ccCanFail: 522 expected = nil 523 expectRC = 0 524 default: 525 rc := err.(*exec.ExitError).ProcessState.ExitCode() 526 if rc != expectRC { 527 return nil, skipErr(fmt.Sprintf("executing CC binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, expected)), ccTime, ccgoTime 528 } 529 530 err = nil 531 } 532 } 533 534 if *oTraceO { 535 switch { 536 case t.hasBinaryOutput: 537 fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", ccTime, args, binaryBytes) 538 default: 539 fmt.Fprintf(os.Stderr, "%v %q: %s\n", ccTime, args, expected) 540 } 541 } 542 } 543 544 if t.cmd == "" { 545 if err := os.Remove(binary); err != nil { 546 return nil, fmt.Errorf("removing %v: %v", binary, err), ccTime, ccgoTime 547 } 548 } 549 550 ccgoArgs := append([]string(nil), t.opts...) 551 ccgoArgs = append(ccgoArgs, "-D__ccgo_test__", "-export-fields", "F", "-ignore-unsupported-alignment") 552 if *oFullPaths { 553 ccgoArgs = append(ccgoArgs, "-full-paths-comments") 554 } 555 if binary, err = makeBinary(t.src, t.doNotExec, ccgoArgs...); err != nil { 556 return nil, err, ccTime, ccgoTime 557 } 558 559 var got []byte 560 if !t.doNotExec { 561 ctx, cancel := context.WithTimeout(context.Background(), execTimeout) 562 defer cancel() 563 if t.cmd != "" { 564 binary = t.cmd 565 } 566 if len(t.args) != 0 { 567 args = t.args 568 } 569 t0 := time.Now() 570 if *oTrc2 { 571 fmt.Fprintf(os.Stderr, "%v: started ccgo binary for %s: %v %v\n", t0, baseName, binary, args) 572 } 573 switch { 574 case t.hasBinaryOutput: 575 binaryBytes2, err = execute(ctx, binary, ccgoOut, args) 576 defer os.Remove(ccgoOut) 577 default: 578 if got, err = testSingleCombinedoutput(ctx, exec.CommandContext(ctx, binary, args...)); len(got) > outLimit { 579 panic(todo("", t.src, len(expected))) 580 } 581 } 582 ccgoTime = time.Since(t0) 583 if *oTrc2 { 584 switch { 585 case t.hasBinaryOutput: 586 fmt.Fprintf(os.Stderr, "%v: ccgo binary for %s returned: %v bytes, err %v\n", time.Now(), baseName, binaryBytes2, err) 587 default: 588 fmt.Fprintf(os.Stderr, "%v: ccgo binary for %s returned: err %v\n%s\n", time.Now(), baseName, err, got) 589 } 590 } 591 if err != nil { 592 rc := err.(*exec.ExitError).ProcessState.ExitCode() 593 if rc != expectRC { 594 return nil, fmt.Errorf("executing ccgo binary %v %v: %v (rc %v, expected %v)\n%s", binary, args, err, rc, expectRC, got), ccTime, ccgoTime 595 } 596 597 err = nil 598 } 599 600 if *oTraceO { 601 switch { 602 case t.hasBinaryOutput: 603 fmt.Fprintf(os.Stderr, "%v %q: %d bytes\n", ccgoTime, args, binaryBytes2) 604 default: 605 fmt.Fprintf(os.Stderr, "%v %q: %s\n", ccgoTime, args, got) 606 } 607 } 608 switch { 609 case t.hasBinaryOutput: 610 if err := fileEqual(ccgoOut, ccOut); err != nil { 611 return nil, fmt.Errorf("binary output: %s", err), ccTime, ccgoTime 612 } 613 default: 614 got := string(got) 615 expected := string(expected) 616 got = strings.ReplaceAll(got, "\r", "") 617 got = lineTrim(strings.TrimSpace(got)) 618 expected = strings.ReplaceAll(expected, "\r", "") 619 expected = lineTrim(strings.TrimSpace(expected)) 620 if got != expected { 621 diff := difflib.UnifiedDiff{ 622 A: difflib.SplitLines(expected), 623 B: difflib.SplitLines(got), 624 FromFile: "expected", 625 ToFile: "got", 626 Context: 3, 627 } 628 text, _ := difflib.GetUnifiedDiffString(diff) 629 return nil, fmt.Errorf( 630 "%v: text output differs:\n%s\n---- x.c\ngot\n%s\nexp\n%s\ngot\n%s\nexp\n%s", 631 t.src, text, 632 hex.Dump([]byte(got)), hex.Dump([]byte(expected)), 633 got, expected, 634 ), ccTime, ccgoTime 635 } 636 } 637 } 638 return got, err, ccTime, ccgoTime 639 } 640 641 func lineTrim(s string) string { 642 a := strings.Split(s, "\n") 643 for i, v := range a { 644 a[i] = strings.TrimSpace(v) 645 } 646 return strings.Join(a, "\n") 647 } 648 649 func fileEqual(g, e string) error { 650 fig, err := os.Stat(g) 651 if err != nil { 652 return err 653 } 654 655 fie, err := os.Stat(e) 656 if err != nil { 657 return err 658 } 659 660 if g, e := fig.Size(), fie.Size(); g != e { 661 return fmt.Errorf("files sizes differ, got %v, expected %v", g, e) 662 } 663 664 rem := fig.Size() 665 if rem == 0 { 666 return nil 667 } 668 669 var bg, be [4096]byte 670 fg, err := os.Open(g) 671 if err != nil { 672 return err 673 } 674 675 defer fg.Close() 676 677 fe, err := os.Open(e) 678 if err != nil { 679 return err 680 } 681 682 defer fe.Close() 683 684 for rem != 0 { 685 n, err := io.ReadFull(fg, bg[:]) 686 if n == 0 { 687 if err == io.EOF { 688 err = nil 689 } 690 return err 691 } 692 693 n2, err := io.ReadFull(fe, be[:]) 694 if n == 0 { 695 if err == io.EOF { 696 err = nil 697 } 698 return err 699 } 700 701 if n != n2 { 702 panic(todo("", n, n2)) 703 } 704 705 if !bytes.Equal(bg[:n], be[:n]) { 706 return fmt.Errorf("files are different") 707 } 708 709 rem -= int64(n) 710 } 711 return nil 712 } 713 714 var ftoken uint32 715 716 func newID() uint32 { return atomic.AddUint32(&ftoken, 1) } 717 718 func makeBinary(src string, obj bool, args ...string) (executable string, err error) { 719 defer func() { 720 if err != nil { 721 if *oTrace { 722 fmt.Println(err) 723 } 724 err = cpp(*oCpp, args, err) 725 err = fmt.Errorf("%s: %v", src, err) 726 } 727 }() 728 729 pkg := "main" 730 if obj { 731 pkg = "foo" 732 } 733 734 main := fmt.Sprintf("main%d.go", newID()) 735 src = filepath.Base(src) 736 if err := NewTask(append([]string{"ccgo", "-o", main, "-pkgname", pkg, "-nocapi", src}, args...), nil, nil).Main(); err != nil { 737 return "", err 738 } 739 740 if *oTraceF { 741 b, _ := ioutil.ReadFile(main) 742 fmt.Printf("\n----\n%s\n----\n", b) 743 } 744 745 executable = fmt.Sprintf("./%s%d", src[:len(src)-len(filepath.Ext(src))], newID()) 746 var ext string 747 if runtime.GOOS == "windows" { 748 ext = ".exe" 749 } 750 executable += ext 751 os.Remove(executable) 752 var b []byte 753 switch { 754 case obj: 755 b, err = exec.Command("go", "build", main).CombinedOutput() 756 default: 757 b, err = exec.Command("go", "build", "-o", executable, main).CombinedOutput() 758 } 759 if err != nil { 760 err = fmt.Errorf("%s\n\tFAIL: %v", b, err) 761 } 762 return executable, err 763 } 764 765 type countingWriter struct { 766 written int 767 w *bufio.Writer 768 } 769 770 func (c *countingWriter) Write(b []byte) (int, error) { 771 n, err := c.w.Write(b) 772 c.written += n 773 return n, err 774 } 775 776 var _ io.Writer = (*countingWriter)(nil) 777 778 // err = execute(ctx, executable, args, ccOut) 779 func execute(ctx context.Context, executable, out string, args []string) (n int, err error) { 780 cmd := exec.CommandContext(ctx, executable, args...) 781 f, err := os.Create(out) 782 if err != nil { 783 return 0, err 784 } 785 786 defer func() { 787 if e := f.Close(); e != nil && err == nil { 788 err = e 789 } 790 }() 791 792 w := &countingWriter{w: bufio.NewWriter(f)} 793 794 defer func() { 795 if e := w.w.Flush(); e != nil && err == nil { 796 err = e 797 } 798 }() 799 800 cmd.Stdout = w 801 err = testSingleRun(ctx, cmd) 802 return w.written, err 803 } 804 805 func makeCCBinary(src string, obj bool, args ...string) (executable string, err error) { 806 ext := "" 807 if obj { 808 ext = ".o" 809 } 810 src = filepath.Base(src) 811 executable = "./" + src[:len(src)-len(filepath.Ext(src))] 812 if runtime.GOOS == "windows" && !obj { 813 ext = ".exe" 814 } 815 executable += ext 816 os.Remove(executable) 817 b, err := exec.Command(systemCC, append([]string{"-o", executable, src}, args...)...).CombinedOutput() 818 if err != nil { 819 return "", fmt.Errorf("%v %v -o %v %v: system C compiler: %v\n%s", systemCC, args, executable, src, err, b) 820 } 821 822 return executable, nil 823 } 824 825 func getArgs(src string) (args []string, err error) { 826 src = src[:len(src)-len(filepath.Ext(src))] + ".arg" 827 overlay := filepath.Join(overlayDir, src) 828 b, err := ioutil.ReadFile(overlay) 829 if err != nil { 830 if !os.IsNotExist(err) { 831 return nil, err 832 } 833 834 f, err := fs.Open(src) 835 if err != nil { 836 return nil, nil 837 } 838 839 if b, err = ioutil.ReadAll(f); err != nil { 840 return nil, err 841 } 842 843 if err = f.Close(); err != nil { 844 return nil, err 845 } 846 } 847 848 a := strings.Split(strings.TrimSpace(string(b)), "\n") 849 for _, v := range a { 850 switch { 851 case strings.HasPrefix(v, "\"") || strings.HasPrefix(v, "`"): 852 w, err := strconv.Unquote(v) 853 if err != nil { 854 return nil, fmt.Errorf("%s: %v: %v", src, v, err) 855 } 856 857 args = append(args, w) 858 default: 859 args = append(args, v) 860 } 861 } 862 return args, nil 863 } 864 865 func TestTCC(t *testing.T) { 866 const root = "/tcc-0.9.27/tests/tests2" 867 g := newGolden(t, fmt.Sprintf("testdata/tcc_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 868 869 defer g.close() 870 871 mustEmptyDir(t, tempDir, keep) 872 wd, err := os.Getwd() 873 if err != nil { 874 t.Fatal(err) 875 } 876 877 if err := os.Chdir(tempDir); err != nil { 878 t.Fatal(err) 879 } 880 881 defer func() { 882 if err := os.Chdir(wd); err != nil { 883 t.Fatal(err) 884 } 885 }() 886 887 needFiles(t, root, []string{ 888 "18_include.h", 889 "95_bitfields.c", 890 }) 891 blacklist := map[string]struct{}{ 892 "60_errors_and_warnings.c": {}, // no main 893 "73_arm64.c": {}, // does not work properly on any gcc tested (7-11) 894 "76_dollars_in_identifiers.c": {}, // `int $ = 10;` etc. 895 "77_push_pop_macro.c": {}, // unsupported push/pop macro 896 "78_vla_label.c": {}, //MAYBE 897 "79_vla_continue.c": {}, //MAYBE 898 "80_flexarray.c": {}, //MAYBE 899 "83_utf8_in_identifiers.c": {}, // No support before gcc 10. 900 "85_asm-outside-function.c": {}, // asm 901 "90_struct-init.c": {}, // 90_struct-init.c:168:25: `...`: expected ] 902 "94_generic.c": {}, // 94_generic.c:36:18: `int`: expected primary-expression 903 "95_bitfields.c": {}, // Included from 95_bitfields_ms.c 904 "96_nodata_wanted.c": {}, // no main 905 "98_al_ax_extend.c": {}, // asm 906 "99_fastcall.c": {}, // asm 907 908 "95_bitfields_ms.c": {}, //TODO 909 } 910 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 911 case "linux/s390x": 912 blacklist["function forward decl 2.c"] = struct{}{} //TODO 913 blacklist["if bool eq int 0.c"] = struct{}{} //TODO 914 case "freebsd/amd64": 915 blacklist["40_stdio.c"] = struct{}{} //TODO 916 case "netbsd/amd64": 917 blacklist["40_stdio.c"] = struct{}{} //TODO 918 } 919 var rq, res, ok int 920 limit := runtime.GOMAXPROCS(0) 921 limiter := make(chan struct{}, limit) 922 success := make([]string, 0, 0) 923 results := make(chan *runResult, limit) 924 failed := map[string]struct{}{} 925 err = walk(root, func(pth string, fi os.FileInfo) error { 926 if !strings.HasSuffix(pth, ".c") { 927 return nil 928 } 929 930 switch { 931 case re != nil: 932 if !re.MatchString(pth) { 933 return nil 934 } 935 default: 936 if _, ok := blacklist[filepath.Base(pth)]; ok { 937 return nil 938 } 939 } 940 941 more: 942 select { 943 case r := <-results: 944 res++ 945 <-limiter 946 switch r.err.(type) { 947 case nil: 948 ok++ 949 success = append(success, filepath.Base(r.name)) 950 delete(failed, r.name) 951 case skipErr: 952 delete(failed, r.name) 953 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 954 default: 955 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 956 } 957 goto more 958 case limiter <- struct{}{}: 959 rq++ 960 if *oTrace { 961 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 962 } 963 failed[pth] = struct{}{} 964 go run(pth, false, false, false, results) 965 } 966 return nil 967 }) 968 if err != nil { 969 t.Fatal(err) 970 } 971 for res != rq { 972 r := <-results 973 res++ 974 <-limiter 975 switch r.err.(type) { 976 case nil: 977 ok++ 978 success = append(success, filepath.Base(r.name)) 979 delete(failed, r.name) 980 case skipErr: 981 delete(failed, r.name) 982 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 983 default: 984 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 985 } 986 } 987 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 988 sort.Strings(success) 989 for _, fpath := range success { 990 g.w.Write([]byte(fpath)) 991 g.w.Write([]byte{'\n'}) 992 } 993 if len(failed) == 0 { 994 return 995 } 996 997 var a []string 998 for k := range failed { 999 a = append(a, k) 1000 } 1001 sort.Strings(a) 1002 for _, v := range a { 1003 t.Logf("FAIL %s", v) 1004 } 1005 } 1006 1007 func run(src string, binaryOut, ccCanFail, doNotExec bool, c chan *runResult, opts ...string) { 1008 (&runTask{ 1009 c: c, 1010 ccCanFail: ccCanFail, 1011 doNotExec: doNotExec, 1012 hasBinaryOutput: binaryOut, 1013 opts: opts, 1014 src: src, 1015 }).run() 1016 } 1017 1018 func walk(dir string, f func(pth string, fi os.FileInfo) error) error { 1019 if !strings.HasSuffix(dir, "/") { 1020 dir += "/" 1021 } 1022 root, err := fs.Open(dir) 1023 if err != nil { 1024 return err 1025 } 1026 1027 fi, err := root.Stat() 1028 if err != nil { 1029 return err 1030 } 1031 1032 if !fi.IsDir() { 1033 return fmt.Errorf("%s: not a directory", fi.Name()) 1034 } 1035 1036 fis, err := root.Readdir(-1) 1037 if err != nil { 1038 return err 1039 } 1040 1041 for _, v := range fis { 1042 switch { 1043 case v.IsDir(): 1044 if err = walk(v.Name(), f); err != nil { 1045 return err 1046 } 1047 default: 1048 if err = f(v.Name(), v); err != nil { 1049 return err 1050 } 1051 } 1052 } 1053 return nil 1054 } 1055 1056 func needFiles(t *testing.T, root string, a []string) { 1057 for _, v := range a { 1058 overlay := filepath.Join(overlayDir, filepath.FromSlash(root), v) 1059 b, err := ioutil.ReadFile(overlay) 1060 if err != nil { 1061 if !os.IsNotExist(err) { 1062 t.Fatal(err) 1063 } 1064 1065 f, err := fs.Open(path.Join(root, v)) 1066 if err != nil { 1067 t.Fatal(err) 1068 } 1069 1070 if b, err = ioutil.ReadAll(f); err != nil { 1071 t.Fatal(err) 1072 } 1073 1074 if err = f.Close(); err != nil { 1075 t.Fatal(err) 1076 } 1077 } 1078 if dir, _ := filepath.Split(v); dir != "" { 1079 if err := os.MkdirAll(dir, 0700); err != nil { 1080 t.Fatal(err) 1081 } 1082 } 1083 1084 if err := ioutil.WriteFile(v, b, 0600); err != nil { 1085 t.Fatal(err) 1086 } 1087 } 1088 } 1089 1090 func mustEmptyDir(t *testing.T, s string, keep map[string]struct{}) { 1091 if err := emptyDir(s, keep); err != nil { 1092 t.Fatal(err) 1093 } 1094 } 1095 1096 func emptyDir(s string, keep map[string]struct{}) error { 1097 m, err := filepath.Glob(filepath.FromSlash(s + "/*")) 1098 if err != nil { 1099 return err 1100 } 1101 1102 for _, v := range m { 1103 fi, err := os.Stat(v) 1104 if err != nil { 1105 return err 1106 } 1107 1108 switch { 1109 case fi.IsDir(): 1110 if err = os.RemoveAll(v); err != nil { 1111 return err 1112 } 1113 default: 1114 if _, ok := keep[filepath.Base(v)]; ok { 1115 break 1116 } 1117 1118 if err = os.Remove(v); err != nil { 1119 return err 1120 } 1121 } 1122 } 1123 return nil 1124 } 1125 1126 func cpp(enabled bool, args []string, err0 error) error { 1127 if !enabled { 1128 return err0 1129 } 1130 1131 args = append(args, "-E") 1132 var out bytes.Buffer 1133 if err := NewTask(args, &out, &out).Main(); err != nil { 1134 return fmt.Errorf("error while acquiring preprocessor output: %v\n%v", err, err0) 1135 } 1136 1137 return fmt.Errorf("preprocessor output:\n%s\n%v", out.Bytes(), err0) 1138 } 1139 1140 func trim(b []byte) (r []byte) { 1141 b = bytes.ReplaceAll(b, []byte{'\r'}, nil) 1142 b = bytes.TrimLeft(b, "\n") 1143 b = bytes.TrimRight(b, "\n") 1144 a := bytes.Split(b, []byte("\n")) 1145 for i, v := range a { 1146 a[i] = bytes.TrimRight(v, " ") 1147 } 1148 return bytes.Join(a, []byte("\n")) 1149 } 1150 1151 func noExt(s string) string { 1152 ext := filepath.Ext(s) 1153 if ext == "" { 1154 panic("internal error") //TODOOK 1155 } 1156 return s[:len(s)-len(ext)] 1157 } 1158 1159 func copyFile(src, dst string) error { 1160 b, err := ioutil.ReadFile(src) 1161 if err != nil { 1162 return err 1163 } 1164 1165 return ioutil.WriteFile(dst, b, 0660) 1166 } 1167 1168 func skipDir(path string) error { 1169 if strings.HasPrefix(filepath.Base(path), ".") { 1170 return filepath.SkipDir 1171 } 1172 1173 return nil 1174 } 1175 1176 func TestCAPI(t *testing.T) { 1177 task := NewTask(nil, nil, nil) 1178 pkgName, capi, err := task.capi("modernc.org/libc") 1179 if err != nil { 1180 t.Fatal(err) 1181 } 1182 1183 if _, ok := capi["printf"]; !ok { 1184 t.Fatal("default libc does not export printf") 1185 } 1186 1187 t.Log(pkgName, capi) 1188 } 1189 1190 const text = "abcd\nefgh\x00ijkl" 1191 1192 var ( 1193 text1 = text 1194 text2 = (*reflect.StringHeader)(unsafe.Pointer(&text1)).Data 1195 ) 1196 1197 func TestText(t *testing.T) { 1198 p := text2 1199 var b []byte 1200 for i := 0; i < len(text); i++ { 1201 b = append(b, *(*byte)(unsafe.Pointer(p))) 1202 p++ 1203 } 1204 if g, e := string(b), text; g != e { 1205 t.Fatalf("%q %q", g, e) 1206 } 1207 } 1208 1209 func TestMirBenchmarks(t *testing.T) { 1210 const root = "/github.com/vnmakarov/mir/c-benchmarks" 1211 g := newGolden(t, fmt.Sprintf("testdata/mir_c_benchmarks_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1212 1213 defer g.close() 1214 1215 mustEmptyDir(t, tempDir, keep) 1216 wd, err := os.Getwd() 1217 if err != nil { 1218 t.Fatal(err) 1219 } 1220 1221 if err := os.Chdir(tempDir); err != nil { 1222 t.Fatal(err) 1223 } 1224 1225 defer func() { 1226 if err := os.Chdir(wd); err != nil { 1227 t.Fatal(err) 1228 } 1229 }() 1230 1231 needFiles(t, root, []string{ 1232 "simple_hash.h", 1233 }) 1234 blacklist := map[string]struct{}{ 1235 "except.c": {}, // longjmp 1236 } 1237 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 1238 case "darwin/amd64": 1239 blacklist["method-call.c"] = struct{}{} //TODO 1240 case "darwin/arm64": 1241 blacklist["method-call.c"] = struct{}{} //TODO 1242 case "windows/amd64": 1243 blacklist["except.c"] = struct{}{} //TODO 1244 blacklist["mandelbrot.c"] = struct{}{} //TODO 1245 case "windows/arm64": 1246 blacklist["except.c"] = struct{}{} //TODO 1247 blacklist["mandelbrot.c"] = struct{}{} //TODO 1248 case "windows/386": 1249 blacklist["mandelbrot.c"] = struct{}{} //TODO 1250 case "linux/s390x": 1251 blacklist["mandelbrot.c"] = struct{}{} //TODO 1252 } 1253 binary := map[string]bool{ 1254 "mandelbrot.c": true, 1255 } 1256 var rq, res, ok int 1257 limit := runtime.GOMAXPROCS(0) 1258 limiter := make(chan struct{}, limit) 1259 success := make([]string, 0, 0) 1260 results := make(chan *runResult, limit) 1261 failed := map[string]struct{}{} 1262 err = walk(root, func(pth string, fi os.FileInfo) error { 1263 if !strings.HasSuffix(pth, ".c") { 1264 return nil 1265 } 1266 1267 switch { 1268 case re != nil: 1269 if !re.MatchString(pth) { 1270 return nil 1271 } 1272 default: 1273 if _, ok := blacklist[filepath.Base(pth)]; ok { 1274 return nil 1275 } 1276 } 1277 1278 more: 1279 select { 1280 case r := <-results: 1281 res++ 1282 <-limiter 1283 switch r.err.(type) { 1284 case nil: 1285 ok++ 1286 success = append(success, filepath.Base(r.name)) 1287 delete(failed, r.name) 1288 case skipErr: 1289 delete(failed, r.name) 1290 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1291 default: 1292 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1293 } 1294 goto more 1295 case limiter <- struct{}{}: 1296 rq++ 1297 if *oTrace { 1298 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 1299 } 1300 failed[pth] = struct{}{} 1301 go run(pth, binary[filepath.Base(pth)], false, false, results) 1302 } 1303 return nil 1304 }) 1305 if err != nil { 1306 t.Fatal(err) 1307 } 1308 for res != rq { 1309 r := <-results 1310 res++ 1311 <-limiter 1312 switch r.err.(type) { 1313 case nil: 1314 ok++ 1315 success = append(success, filepath.Base(r.name)) 1316 delete(failed, r.name) 1317 case skipErr: 1318 delete(failed, r.name) 1319 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1320 default: 1321 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1322 } 1323 } 1324 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 1325 sort.Strings(success) 1326 for _, fpath := range success { 1327 g.w.Write([]byte(fpath)) 1328 g.w.Write([]byte{'\n'}) 1329 } 1330 if len(failed) == 0 { 1331 return 1332 } 1333 1334 var a []string 1335 for k := range failed { 1336 a = append(a, k) 1337 } 1338 sort.Strings(a) 1339 for _, v := range a { 1340 t.Logf("FAIL %s", v) 1341 } 1342 } 1343 1344 func TestMirAndrewChambers(t *testing.T) { 1345 const root = "/github.com/vnmakarov/mir/c-tests/andrewchambers_c" 1346 g := newGolden(t, fmt.Sprintf("testdata/mir_andrew_chambers_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1347 1348 defer g.close() 1349 1350 mustEmptyDir(t, tempDir, keep) 1351 wd, err := os.Getwd() 1352 if err != nil { 1353 t.Fatal(err) 1354 } 1355 1356 if err := os.Chdir(tempDir); err != nil { 1357 t.Fatal(err) 1358 } 1359 1360 defer func() { 1361 if err := os.Chdir(wd); err != nil { 1362 t.Fatal(err) 1363 } 1364 }() 1365 1366 blacklist := map[string]struct{}{ 1367 "0011-switch1.c": {}, //TODO 1368 "0025-duff.c": {}, //TODO 1369 "0028-inits06.c": {}, //TODO 1370 "0028-inits10.c": {}, //TODO 1371 "0028-inits11.c": {}, //TODO 1372 "0028-inits12.c": {}, //TODO 1373 "0028-inits13.c": {}, //TODO 1374 "0028-inits15.c": {}, //TODO 1375 } 1376 binary := map[string]bool{} 1377 var rq, res, ok int 1378 limit := runtime.GOMAXPROCS(0) 1379 limiter := make(chan struct{}, limit) 1380 success := make([]string, 0, 0) 1381 results := make(chan *runResult, limit) 1382 failed := map[string]struct{}{} 1383 err = walk(root, func(pth string, fi os.FileInfo) error { 1384 if !strings.HasSuffix(pth, ".c") { 1385 return nil 1386 } 1387 1388 switch { 1389 case re != nil: 1390 if !re.MatchString(pth) { 1391 return nil 1392 } 1393 default: 1394 if _, ok := blacklist[filepath.Base(pth)]; ok { 1395 return nil 1396 } 1397 } 1398 1399 more: 1400 select { 1401 case r := <-results: 1402 res++ 1403 <-limiter 1404 switch r.err.(type) { 1405 case nil: 1406 ok++ 1407 success = append(success, filepath.Base(r.name)) 1408 delete(failed, r.name) 1409 case skipErr: 1410 delete(failed, r.name) 1411 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1412 default: 1413 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1414 } 1415 goto more 1416 case limiter <- struct{}{}: 1417 rq++ 1418 if *oTrace { 1419 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 1420 } 1421 failed[pth] = struct{}{} 1422 go run(pth, binary[filepath.Base(pth)], false, false, results) 1423 } 1424 return nil 1425 }) 1426 if err != nil { 1427 t.Fatal(err) 1428 } 1429 for res != rq { 1430 r := <-results 1431 res++ 1432 <-limiter 1433 switch r.err.(type) { 1434 case nil: 1435 ok++ 1436 success = append(success, filepath.Base(r.name)) 1437 delete(failed, r.name) 1438 case skipErr: 1439 delete(failed, r.name) 1440 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1441 default: 1442 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1443 } 1444 } 1445 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 1446 sort.Strings(success) 1447 for _, fpath := range success { 1448 g.w.Write([]byte(fpath)) 1449 g.w.Write([]byte{'\n'}) 1450 } 1451 if len(failed) == 0 { 1452 return 1453 } 1454 1455 var a []string 1456 for k := range failed { 1457 a = append(a, k) 1458 } 1459 sort.Strings(a) 1460 for _, v := range a { 1461 t.Logf("FAIL %s", v) 1462 } 1463 } 1464 1465 func TestMirLacc(t *testing.T) { 1466 const root = "/github.com/vnmakarov/mir/c-tests/lacc" 1467 g := newGolden(t, fmt.Sprintf("testdata/mir_lacc_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1468 1469 defer g.close() 1470 1471 mustEmptyDir(t, tempDir, keep) 1472 wd, err := os.Getwd() 1473 if err != nil { 1474 t.Fatal(err) 1475 } 1476 1477 if err := os.Chdir(tempDir); err != nil { 1478 t.Fatal(err) 1479 } 1480 1481 defer func() { 1482 if err := os.Chdir(wd); err != nil { 1483 t.Fatal(err) 1484 } 1485 }() 1486 1487 needFiles(t, root, []string{ 1488 "hello.c", 1489 "header.h", 1490 }) 1491 blacklist := map[string]struct{}{ 1492 "anonymous-struct.c": {}, //TODO 1493 "array-registers.c": {}, //TODO 1494 "bitfield-basic.c": {}, //TODO 1495 "bitfield-extend.c": {}, //TODO 1496 "bitfield-pack-next.c": {}, //TODO 1497 "bitfield-trailing-zero.c": {}, //TODO 1498 "bitfield-types-init.c": {}, //TODO 1499 "bitfield.c": {}, //TODO 1500 "conditional-void.c": {}, //TODO 1501 "declarator-complex.c": {}, //TODO 1502 "duffs-device.c": {}, //TODO 1503 "function-incomplete.c": {}, //TODO 1504 "function-pointer-call.c": {}, //TODO 1505 "function-pointer.c": {}, //TODO 1506 "function.c": {}, //TODO 1507 "hello.c": {}, //TODO 1508 "immediate-expr.c": {}, //TODO 1509 "include.c": {}, //TODO 1510 "ldouble-load-direct.c": {}, //TODO 1511 "long-double-arithmetic.c": {}, //TODO 1512 "long-double-compare.c": {}, //TODO 1513 "long-double-function.c": {}, //TODO 1514 "long-double-load.c": {}, //TODO 1515 "long-double-struct.c": {}, //TODO 1516 "long-double-union.c": {}, //TODO 1517 "macro-paste.c": {}, //TODO 1518 "macro.c": {}, //TODO 1519 "pointer.c": {}, //TODO 1520 "string-addr.c": {}, //TODO 1521 "string-concat.c": {}, //TODO 1522 "string-escape.c": {}, //TODO 1523 "string-index.c": {}, //TODO 1524 "string-length.c": {}, //TODO 1525 "stringify.c": {}, //TODO 1526 "strings.c": {}, //TODO 1527 "token.c": {}, //TODO 1528 "typedef.c": {}, //TODO 1529 "union-bitfield.c": {}, //TODO 1530 "vararg-complex-1.c": {}, //TODO 1531 "vararg-complex-2.c": {}, //TODO 1532 "vararg.c": {}, //TODO 1533 "whitespace.c": {}, //TODO 1534 } 1535 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 1536 case "linux/386": 1537 blacklist["convert-unsigned-float.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 ? 1538 case "freebsd/386": 1539 blacklist["convert-unsigned-float.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 ? 1540 case "windows/amd64": 1541 blacklist["convert-unsigned-float.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 ? 1542 blacklist["immediate-pointer.c"] = struct{}{} //TODO 1543 blacklist["unsigned-sign-extend.c"] = struct{}{} //TODO 1544 case "windows/arm64": 1545 blacklist["convert-unsigned-float.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 ? 1546 blacklist["immediate-pointer.c"] = struct{}{} //TODO 1547 blacklist["unsigned-sign-extend.c"] = struct{}{} //TODO 1548 case "windows/386": 1549 blacklist["convert-unsigned-float.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 ? 1550 blacklist["unsigned-sign-extend.c"] = struct{}{} //TODO 1551 } 1552 binary := map[string]bool{} 1553 var rq, res, ok int 1554 limit := runtime.GOMAXPROCS(0) 1555 limiter := make(chan struct{}, limit) 1556 success := make([]string, 0, 0) 1557 results := make(chan *runResult, limit) 1558 failed := map[string]struct{}{} 1559 err = walk(root, func(pth string, fi os.FileInfo) error { 1560 if !strings.HasSuffix(pth, ".c") { 1561 return nil 1562 } 1563 1564 switch { 1565 case re != nil: 1566 if !re.MatchString(pth) { 1567 return nil 1568 } 1569 default: 1570 if _, ok := blacklist[filepath.Base(pth)]; ok { 1571 return nil 1572 } 1573 } 1574 1575 more: 1576 select { 1577 case r := <-results: 1578 res++ 1579 <-limiter 1580 switch r.err.(type) { 1581 case nil: 1582 ok++ 1583 success = append(success, filepath.Base(r.name)) 1584 delete(failed, r.name) 1585 case skipErr: 1586 delete(failed, r.name) 1587 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1588 default: 1589 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1590 } 1591 goto more 1592 case limiter <- struct{}{}: 1593 rq++ 1594 if *oTrace { 1595 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 1596 } 1597 failed[pth] = struct{}{} 1598 go run(pth, binary[filepath.Base(pth)], false, false, results) 1599 } 1600 return nil 1601 }) 1602 if err != nil { 1603 t.Fatal(err) 1604 } 1605 for res != rq { 1606 r := <-results 1607 res++ 1608 <-limiter 1609 switch r.err.(type) { 1610 case nil: 1611 ok++ 1612 success = append(success, filepath.Base(r.name)) 1613 delete(failed, r.name) 1614 case skipErr: 1615 delete(failed, r.name) 1616 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1617 default: 1618 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1619 } 1620 } 1621 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 1622 sort.Strings(success) 1623 for _, fpath := range success { 1624 g.w.Write([]byte(fpath)) 1625 g.w.Write([]byte{'\n'}) 1626 } 1627 if len(failed) == 0 { 1628 return 1629 } 1630 1631 var a []string 1632 for k := range failed { 1633 a = append(a, k) 1634 } 1635 sort.Strings(a) 1636 for _, v := range a { 1637 t.Logf("FAIL %s", v) 1638 } 1639 } 1640 1641 func TestMirNew(t *testing.T) { 1642 const root = "/github.com/vnmakarov/mir/c-tests/new" 1643 g := newGolden(t, fmt.Sprintf("testdata/mir_new_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1644 1645 defer g.close() 1646 1647 mustEmptyDir(t, tempDir, keep) 1648 wd, err := os.Getwd() 1649 if err != nil { 1650 t.Fatal(err) 1651 } 1652 1653 if err := os.Chdir(tempDir); err != nil { 1654 t.Fatal(err) 1655 } 1656 1657 defer func() { 1658 if err := os.Chdir(wd); err != nil { 1659 t.Fatal(err) 1660 } 1661 }() 1662 1663 blacklist := map[string]struct{}{ 1664 // 1: /github.com/vnmakarov/mir/c-tests/new/endif.c 1665 // all_test.go:1045: /github.com/vnmakarov/mir/c-tests/new/endif.c: /usr/bin/gcc: system C compiler: exit status 1 1666 // endif.c:1:2: error: #endif without #if 1667 // #endif 1668 // ^~~~~ 1669 "endif.c": {}, // No intent to support. 1670 1671 // 1: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c 1672 // all_test.go:1051: /github.com/vnmakarov/mir/c-tests/new/fermian-2.c: /usr/bin/gcc: system C compiler: exit status 1 1673 // fermian-2.c:1:3: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘{’ token 1674 // a { 1675 // ^ 1676 "fermian-2.c": {}, // No intent to support. 1677 "fermian.c": {}, // No main. 1678 1679 "issue142.c": {}, //TODO 1680 "issue18.c": {}, //TODO 1681 "issue23.c": {}, //TODO 1682 "setjmp.c": {}, //TODO 1683 "setjmp2.c": {}, //TODO 1684 } 1685 binary := map[string]bool{} 1686 var rq, res, ok int 1687 limit := runtime.GOMAXPROCS(0) 1688 limiter := make(chan struct{}, limit) 1689 success := make([]string, 0, 0) 1690 results := make(chan *runResult, limit) 1691 failed := map[string]struct{}{} 1692 err = walk(root, func(pth string, fi os.FileInfo) error { 1693 if !strings.HasSuffix(pth, ".c") { 1694 return nil 1695 } 1696 1697 switch { 1698 case re != nil: 1699 if !re.MatchString(pth) { 1700 return nil 1701 } 1702 default: 1703 if _, ok := blacklist[filepath.Base(pth)]; ok { 1704 return nil 1705 } 1706 } 1707 1708 more: 1709 select { 1710 case r := <-results: 1711 res++ 1712 <-limiter 1713 switch r.err.(type) { 1714 case nil: 1715 ok++ 1716 success = append(success, filepath.Base(r.name)) 1717 delete(failed, r.name) 1718 case skipErr: 1719 delete(failed, r.name) 1720 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1721 default: 1722 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1723 } 1724 goto more 1725 case limiter <- struct{}{}: 1726 rq++ 1727 if *oTrace { 1728 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 1729 } 1730 failed[pth] = struct{}{} 1731 go run(pth, binary[filepath.Base(pth)], false, false, results) 1732 } 1733 return nil 1734 }) 1735 if err != nil { 1736 t.Fatal(err) 1737 } 1738 for res != rq { 1739 r := <-results 1740 res++ 1741 <-limiter 1742 switch r.err.(type) { 1743 case nil: 1744 ok++ 1745 success = append(success, filepath.Base(r.name)) 1746 delete(failed, r.name) 1747 case skipErr: 1748 delete(failed, r.name) 1749 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1750 default: 1751 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1752 } 1753 } 1754 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 1755 sort.Strings(success) 1756 for _, fpath := range success { 1757 g.w.Write([]byte(fpath)) 1758 g.w.Write([]byte{'\n'}) 1759 } 1760 if len(failed) == 0 { 1761 return 1762 } 1763 1764 var a []string 1765 for k := range failed { 1766 a = append(a, k) 1767 } 1768 sort.Strings(a) 1769 for _, v := range a { 1770 t.Logf("FAIL %s", v) 1771 } 1772 } 1773 1774 func TestCompCert(t *testing.T) { 1775 const root = "/github.com/AbsInt/CompCert/test/c/" 1776 g := newGolden(t, fmt.Sprintf("testdata/compcert_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1777 1778 defer g.close() 1779 1780 mustEmptyDir(t, tempDir, keep) 1781 wd, err := os.Getwd() 1782 if err != nil { 1783 t.Fatal(err) 1784 } 1785 1786 if err := os.Chdir(tempDir); err != nil { 1787 t.Fatal(err) 1788 } 1789 1790 defer func() { 1791 if err := os.Chdir(wd); err != nil { 1792 t.Fatal(err) 1793 } 1794 }() 1795 1796 needFiles(t, root, []string{ 1797 "Results/knucleotide-input.txt", 1798 "endian.h", 1799 }) 1800 blacklist := map[string]struct{}{} 1801 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 1802 case "windows/386": 1803 blacklist["bisect.c"] = struct{}{} //TODO 1804 blacklist["fftw.c"] = struct{}{} //TODO 1805 blacklist["mandelbrot.c"] = struct{}{} //TODO 1806 blacklist["perlin.c"] = struct{}{} //TODO 1807 case "windows/amd64": 1808 blacklist["mandelbrot.c"] = struct{}{} //TODO 1809 case "windows/arm64": 1810 blacklist["mandelbrot.c"] = struct{}{} //TODO 1811 } 1812 binary := map[string]bool{ 1813 "mandelbrot.c": true, 1814 } 1815 var rq, res, ok int 1816 limit := runtime.GOMAXPROCS(0) 1817 limiter := make(chan struct{}, limit) 1818 success := make([]string, 0, 0) 1819 results := make(chan *runResult, limit) 1820 failed := map[string]struct{}{} 1821 err = walk(root, func(pth string, fi os.FileInfo) error { 1822 if !strings.HasSuffix(pth, ".c") { 1823 return nil 1824 } 1825 1826 switch { 1827 case re != nil: 1828 if !re.MatchString(pth) { 1829 return nil 1830 } 1831 default: 1832 if _, ok := blacklist[filepath.Base(pth)]; ok { 1833 return nil 1834 } 1835 } 1836 1837 more: 1838 select { 1839 case r := <-results: 1840 res++ 1841 <-limiter 1842 switch r.err.(type) { 1843 case nil: 1844 ok++ 1845 success = append(success, filepath.Base(r.name)) 1846 delete(failed, r.name) 1847 case skipErr: 1848 delete(failed, r.name) 1849 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1850 default: 1851 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1852 } 1853 goto more 1854 case limiter <- struct{}{}: 1855 rq++ 1856 if *oTrace { 1857 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 1858 } 1859 failed[pth] = struct{}{} 1860 go run(pth, binary[filepath.Base(pth)], false, false, results) 1861 } 1862 return nil 1863 }) 1864 if err != nil { 1865 t.Fatal(err) 1866 } 1867 for res != rq { 1868 r := <-results 1869 res++ 1870 <-limiter 1871 switch r.err.(type) { 1872 case nil: 1873 ok++ 1874 success = append(success, filepath.Base(r.name)) 1875 delete(failed, r.name) 1876 case skipErr: 1877 delete(failed, r.name) 1878 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 1879 default: 1880 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 1881 } 1882 } 1883 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 1884 sort.Strings(success) 1885 for _, fpath := range success { 1886 g.w.Write([]byte(fpath)) 1887 g.w.Write([]byte{'\n'}) 1888 } 1889 if len(failed) == 0 { 1890 return 1891 } 1892 1893 var a []string 1894 for k := range failed { 1895 a = append(a, k) 1896 } 1897 sort.Strings(a) 1898 for _, v := range a { 1899 t.Logf("FAIL %s", v) 1900 } 1901 } 1902 1903 func TestGCCExecute(t *testing.T) { 1904 const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute" 1905 g := newGolden(t, fmt.Sprintf("testdata/gcc_exec_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 1906 1907 defer g.close() 1908 1909 mustEmptyDir(t, tempDir, keep) 1910 wd, err := os.Getwd() 1911 if err != nil { 1912 t.Fatal(err) 1913 } 1914 1915 if err := os.Chdir(tempDir); err != nil { 1916 t.Fatal(err) 1917 } 1918 1919 defer func() { 1920 if err := os.Chdir(wd); err != nil { 1921 t.Fatal(err) 1922 } 1923 }() 1924 1925 // Prepare testdata 1926 needFiles(t, root, []string{ 1927 "20040709-2.c", 1928 }) 1929 blacklist := map[string]struct{}{ 1930 // assembler 1931 "20001009-2.c": {}, 1932 1933 // Nested function 1934 "20000822-1.c": {}, 1935 "20010209-1.c": {}, 1936 "20010605-1.c": {}, 1937 1938 // Alignment > 8 1939 "20010904-1.c": {}, 1940 "20010904-2.c": {}, 1941 1942 // Variable sized type 1943 "20040423-1.c": {}, 1944 "20040411-1.c": {}, 1945 1946 // Relies on SIGFPE 1947 "20101011-1.c": {}, 1948 1949 // Relies on gcc instrumentation 1950 "eeprof-1.c": {}, 1951 1952 //TODO back-end: undefined: __builtin_return_address 1953 "20010122-1.c": {}, 1954 1955 //TODO crash in cc 1956 "20010605-2.c": {}, 1957 1958 //TODO flexible array members not supported 1959 "20010924-1.c": {}, 1960 1961 //TODO TODO in go.go 1962 "20000113-1.c": {}, 1963 1964 //TODO relies on link order, libc first 1965 "20021127-1.c": {}, 1966 1967 //TODO #pragma push/pop macro 1968 "pushpop_macro.c": {}, 1969 1970 //TODO not yet classified 1971 "20000801-3.c": {}, //TODO 1972 "20020107-1.c": {}, //TODO 1973 "20020206-2.c": {}, //TODO 1974 "20020227-1.c": {}, //TODO 1975 "20020314-1.c": {}, //TODO 1976 "20020320-1.c": {}, //TODO 1977 "20020411-1.c": {}, //TODO 1978 "20020412-1.c": {}, //TODO 1979 "20021113-1.c": {}, //TODO 1980 "20021120-1.c": {}, //TODO 1981 "20030109-1.c": {}, //TODO 1982 "20030128-1.c": {}, //TODO 1983 "20030222-1.c": {}, //TODO 1984 "20030501-1.c": {}, //TODO 1985 "20030910-1.c": {}, //TODO 1986 "20031003-1.c": {}, //TODO 1987 "20040223-1.c": {}, //TODO 1988 "20040302-1.c": {}, //TODO 1989 "20040308-1.c": {}, //TODO 1990 "20040520-1.c": {}, //TODO 1991 "20040629-1.c": {}, //TODO 1992 "20040705-1.c": {}, //TODO 1993 "20040705-2.c": {}, //TODO 1994 "20040707-1.c": {}, //TODO 1995 "20040709-1.c": {}, //TODO 1996 "20040709-2.c": {}, //TODO 1997 "20040709-3.c": {}, //TODO 1998 "20041011-1.c": {}, //TODO 1999 "20041124-1.c": {}, //TODO 2000 "20041201-1.c": {}, //TODO 2001 "20041214-1.c": {}, //TODO 2002 "20041218-2.c": {}, //TODO 2003 "20050121-1.c": {}, //TODO 2004 "20050316-1.c": {}, //TODO 2005 "20050316-2.c": {}, //TODO 2006 "20050316-3.c": {}, //TODO 2007 "20050604-1.c": {}, //TODO 2008 "20050607-1.c": {}, //TODO 2009 "20050613-1.c": {}, //TODO 2010 "20050929-1.c": {}, //TODO 2011 "20051012-1.c": {}, //TODO 2012 "20060420-1.c": {}, //TODO 2013 "20061220-1.c": {}, //TODO 2014 "20070614-1.c": {}, //TODO 2015 "20070824-1.c": {}, //TODO 2016 "20070919-1.c": {}, //TODO 2017 "20071210-1.c": {}, //TODO 2018 "20071211-1.c": {}, //TODO 2019 "20071220-1.c": {}, //TODO 2020 "20071220-2.c": {}, //TODO 2021 "20080502-1.c": {}, //TODO 2022 "20090219-1.c": {}, //TODO 2023 "20100430-1.c": {}, //TODO 2024 "20121108-1.c": {}, //TODO 2025 "20180921-1.c": {}, //TODO 2026 "920302-1.c": {}, //TODO 2027 "920415-1.c": {}, //TODO 2028 "920428-2.c": {}, //TODO 2029 "920501-1.c": {}, //TODO 2030 "920501-3.c": {}, //TODO 2031 "920501-4.c": {}, //TODO 2032 "920501-5.c": {}, //TODO 2033 "920501-7.c": {}, //TODO 2034 "920612-2.c": {}, //TODO 2035 "920625-1.c": {}, //TODO 2036 "920721-4.c": {}, //TODO 2037 "920908-1.c": {}, //TODO 2038 "921017-1.c": {}, //TODO 2039 "921202-1.c": {}, //TODO 2040 "921208-2.c": {}, //TODO 2041 "921215-1.c": {}, //TODO 2042 "930406-1.c": {}, //TODO 2043 "931002-1.c": {}, //TODO 2044 "931004-10.c": {}, //TODO 2045 "931004-12.c": {}, //TODO 2046 "931004-14.c": {}, //TODO 2047 "931004-2.c": {}, //TODO 2048 "931004-4.c": {}, //TODO 2049 "931004-6.c": {}, //TODO 2050 "931004-8.c": {}, //TODO 2051 "941014-1.c": {}, //TODO 2052 "941202-1.c": {}, //TODO 2053 "960312-1.c": {}, //TODO 2054 "960416-1.c": {}, //TODO 2055 "960512-1.c": {}, //TODO 2056 "970217-1.c": {}, //TODO 2057 "980526-1.c": {}, //TODO 2058 "990130-1.c": {}, //TODO 2059 "990208-1.c": {}, //TODO 2060 "990413-2.c": {}, //TODO 2061 "990524-1.c": {}, //TODO 2062 "991014-1.c": {}, //TODO 2063 "991112-1.c": {}, //TODO 2064 "991227-1.c": {}, //TODO 2065 "alias-2.c": {}, //TODO 2066 "alias-3.c": {}, //TODO 2067 "alias-4.c": {}, //TODO 2068 "align-3.c": {}, //TODO 2069 "align-nest.c": {}, //TODO 2070 "alloca-1.c": {}, //TODO 2071 "anon-1.c": {}, //TODO 2072 "bitfld-3.c": {}, //TODO 2073 "built-in-setjmp.c": {}, //TODO 2074 "builtin-bitops-1.c": {}, //TODO 2075 "builtin-constant.c": {}, //TODO 2076 "builtin-prefetch-3.c": {}, //TODO 2077 "builtin-types-compatible-p.c": {}, //TODO 2078 "call-trap-1.c": {}, //TODO 2079 "comp-goto-1.c": {}, //TODO 2080 "comp-goto-2.c": {}, //TODO 2081 "complex-1.c": {}, //TODO 2082 "complex-2.c": {}, //TODO 2083 "complex-4.c": {}, //TODO 2084 "complex-5.c": {}, //TODO 2085 "complex-6.c": {}, //TODO 2086 "complex-7.c": {}, //TODO 2087 "ffs-1.c": {}, //TODO 2088 "ffs-2.c": {}, //TODO 2089 "fprintf-2.c": {}, //TODO 2090 "frame-address.c": {}, //TODO 2091 "medce-1.c": {}, //TODO 2092 "nest-align-1.c": {}, //TODO 2093 "nest-stdar-1.c": {}, //TODO 2094 "nestfunc-1.c": {}, //TODO 2095 "nestfunc-2.c": {}, //TODO 2096 "nestfunc-3.c": {}, //TODO 2097 "nestfunc-5.c": {}, //TODO 2098 "nestfunc-6.c": {}, //TODO 2099 "nestfunc-7.c": {}, //TODO 2100 "pr17377.c": {}, //TODO 2101 "pr22061-1.c": {}, //TODO 2102 "pr22061-3.c": {}, //TODO 2103 "pr22061-4.c": {}, //TODO 2104 "pr23135.c": {}, //TODO 2105 "pr23324.c": {}, //TODO 2106 "pr23467.c": {}, //TODO 2107 "pr24135.c": {}, //TODO 2108 "pr28289.c": {}, //TODO 2109 "pr28865.c": {}, //TODO 2110 "pr33382.c": {}, //TODO 2111 "pr34154.c": {}, //TODO 2112 "pr35456.c": {}, //TODO 2113 "pr36321.c": {}, //TODO 2114 "pr37780.c": {}, //TODO 2115 "pr38151.c": {}, //TODO 2116 "pr38533.c": {}, //TODO 2117 "pr38969.c": {}, //TODO 2118 "pr39228.c": {}, //TODO 2119 "pr40022.c": {}, //TODO 2120 "pr40657.c": {}, //TODO 2121 "pr41239.c": {}, //TODO 2122 "pr41935.c": {}, //TODO 2123 "pr42248.c": {}, //TODO 2124 "pr43385.c": {}, //TODO 2125 "pr43560.c": {}, //TODO 2126 "pr44575.c": {}, //TODO 2127 "pr45695.c": {}, //TODO 2128 "pr46309.c": {}, //TODO 2129 "pr47237.c": {}, //TODO 2130 "pr49279.c": {}, //TODO 2131 "pr49390.c": {}, //TODO 2132 "pr49644.c": {}, //TODO 2133 "pr51447.c": {}, //TODO 2134 "pr51877.c": {}, //TODO 2135 "pr51933.c": {}, //TODO 2136 "pr52286.c": {}, //TODO 2137 "pr53160.c": {}, //TODO 2138 "pr53645-2.c": {}, //TODO 2139 "pr53645.c": {}, //TODO 2140 "pr56205.c": {}, //TODO 2141 "pr56837.c": {}, //TODO 2142 "pr56866.c": {}, //TODO 2143 "pr56982.c": {}, //TODO 2144 "pr57344-1.c": {}, //TODO 2145 "pr57344-2.c": {}, //TODO 2146 "pr57344-3.c": {}, //TODO 2147 "pr57344-4.c": {}, //TODO 2148 "pr60003.c": {}, //TODO 2149 "pr60960.c": {}, //TODO 2150 "pr61725.c": {}, //TODO 2151 "pr63641.c": {}, //TODO 2152 "pr64006.c": {}, //TODO 2153 "pr64242.c": {}, //TODO 2154 "pr65053-2.c": {}, //TODO 2155 "pr65427.c": {}, //TODO 2156 "pr65648.c": {}, //TODO 2157 "pr65956.c": {}, //TODO 2158 "pr66556.c": {}, //TODO 2159 "pr67037.c": {}, //TODO 2160 "pr68249.c": {}, //TODO 2161 "pr68328.c": {}, //TODO 2162 "pr68381.c": {}, //TODO 2163 "pr69320-2.c": {}, //TODO 2164 "pr70460.c": {}, //TODO 2165 "pr70903.c": {}, //TODO 2166 "pr71494.c": {}, //TODO 2167 "pr71554.c": {}, //TODO 2168 "pr71626-1.c": {}, //TODO 2169 "pr71626-2.c": {}, //TODO 2170 "pr71631.c": {}, //TODO 2171 "pr77767.c": {}, //TODO 2172 "pr78438.c": {}, //TODO 2173 "pr78726.c": {}, //TODO 2174 "pr79354.c": {}, //TODO 2175 "pr79737-2.c": {}, //TODO 2176 "pr80421.c": {}, //TODO 2177 "pr80692.c": {}, //TODO 2178 "pr81588.c": {}, //TODO 2179 "pr82210.c": {}, //TODO 2180 "pr82954.c": {}, //TODO 2181 "pr84478.c": {}, //TODO 2182 "pr84521.c": {}, //TODO 2183 "pr84524.c": {}, //TODO 2184 "pr85156.c": {}, //TODO 2185 "pr85169.c": {}, //TODO 2186 "pr85331.c": {}, //TODO 2187 "pr85529-1.c": {}, //TODO 2188 "pr86528.c": {}, //TODO 2189 "pr89195.c": {}, //TODO 2190 "pr89434.c": {}, //TODO 2191 "pr90311.c": {}, //TODO 2192 "pr91450-1.c": {}, //TODO 2193 "pr91450-2.c": {}, //TODO 2194 "pr91635.c": {}, //TODO 2195 "pr92618.c": {}, //TODO 2196 "pr92904.c": {}, //TODO 2197 "pr93213.c": {}, //TODO 2198 "pr93249.c": {}, //TODO 2199 "pr93434.c": {}, //TODO 2200 "pr93494.c": {}, //TODO 2201 "pr93744-1.c": {}, //TODO 2202 "pr93945.c": {}, //TODO 2203 "pr94130.c": {}, //TODO 2204 "pr94412.c": {}, //TODO 2205 "pr94524-1.c": {}, //TODO 2206 "pr94524-2.c": {}, //TODO 2207 "pr94591.c": {}, //TODO 2208 "pr97325.c": {}, //TODO 2209 "pr98366.c": {}, //TODO 2210 "pr98474.c": {}, //TODO 2211 "pr98681.c": {}, //TODO 2212 "printf-2.c": {}, //TODO 2213 "return-addr.c": {}, //TODO 2214 "scal-to-vec1.c": {}, //TODO 2215 "scal-to-vec2.c": {}, //TODO 2216 "scal-to-vec3.c": {}, //TODO 2217 "simd-1.c": {}, //TODO 2218 "simd-2.c": {}, //TODO 2219 "simd-4.c": {}, //TODO 2220 "simd-5.c": {}, //TODO 2221 "simd-6.c": {}, //TODO 2222 "stdarg-3.c": {}, //TODO 2223 "stkalign.c": {}, //TODO 2224 "strct-stdarg-1.c": {}, //TODO 2225 "strct-varg-1.c": {}, //TODO 2226 "string-opt-18.c": {}, //TODO 2227 "string-opt-5.c": {}, //TODO 2228 "user-printf.c": {}, //TODO 2229 "va-arg-2.c": {}, //TODO 2230 "va-arg-22.c": {}, //TODO 2231 "va-arg-pack-1.c": {}, //TODO 2232 "zero-struct-2.c": {}, //TODO 2233 } 2234 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 2235 case "freebsd/386": 2236 // asm 2237 blacklist["960830-1.c"] = struct{}{} 2238 case "linux/386": 2239 // asm 2240 blacklist["960830-1.c"] = struct{}{} 2241 case "linux/arm64": 2242 blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO 2243 case "linux/s390x": 2244 blacklist["pr58574.c"] = struct{}{} //TODO 2245 blacklist["vfprintf-chk-1.c"] = struct{}{} //TODO 2246 case "windows/amd64": 2247 blacklist["941014-2.c"] = struct{}{} //TODO 2248 blacklist["pr36339.c"] = struct{}{} //TODO 2249 blacklist["pr78622.c"] = struct{}{} //TODO 2250 case "windows/arm64": 2251 blacklist["941014-2.c"] = struct{}{} //TODO 2252 blacklist["pr36339.c"] = struct{}{} //TODO 2253 blacklist["pr61375.c"] = struct{}{} //TODO 2254 blacklist["pr65170.c"] = struct{}{} //TODO 2255 blacklist["pr78622.c"] = struct{}{} //TODO 2256 blacklist["pr84169.c"] = struct{}{} //TODO 2257 case "windows/386": 2258 blacklist["941014-2.c"] = struct{}{} //TODO 2259 blacklist["960830-1.c"] = struct{}{} //TODO 2260 blacklist["pr78622.c"] = struct{}{} //TODO 2261 } 2262 binary := map[string]bool{} 2263 var rq, res, ok int 2264 limit := runtime.GOMAXPROCS(0) 2265 limiter := make(chan struct{}, limit) 2266 success := make([]string, 0, 0) 2267 results := make(chan *runResult, limit) 2268 failed := map[string]struct{}{} 2269 err = walk(root, func(pth string, fi os.FileInfo) error { 2270 if strings.Contains(pth, "/ieee/") || !strings.HasSuffix(pth, ".c") { 2271 return nil 2272 } 2273 2274 switch { 2275 case re != nil: 2276 if !re.MatchString(pth) { 2277 return nil 2278 } 2279 default: 2280 if _, ok := blacklist[filepath.Base(pth)]; ok { 2281 return nil 2282 } 2283 } 2284 2285 more: 2286 select { 2287 case r := <-results: 2288 res++ 2289 <-limiter 2290 switch r.err.(type) { 2291 case nil: 2292 ok++ 2293 success = append(success, filepath.Base(r.name)) 2294 delete(failed, r.name) 2295 case skipErr: 2296 delete(failed, r.name) 2297 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2298 default: 2299 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2300 } 2301 goto more 2302 case limiter <- struct{}{}: 2303 rq++ 2304 if *oTrace { 2305 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 2306 } 2307 base := filepath.Base(pth) 2308 failed[pth] = struct{}{} 2309 go run(pth, binary[base], false, false, results) 2310 } 2311 return nil 2312 }) 2313 if err != nil { 2314 t.Fatal(err) 2315 } 2316 for res != rq { 2317 r := <-results 2318 res++ 2319 <-limiter 2320 switch r.err.(type) { 2321 case nil: 2322 ok++ 2323 success = append(success, filepath.Base(r.name)) 2324 delete(failed, r.name) 2325 case skipErr: 2326 delete(failed, r.name) 2327 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2328 default: 2329 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2330 } 2331 } 2332 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 2333 sort.Strings(success) 2334 for _, fpath := range success { 2335 g.w.Write([]byte(fpath)) 2336 g.w.Write([]byte{'\n'}) 2337 } 2338 if len(failed) == 0 { 2339 return 2340 } 2341 2342 var a []string 2343 for k := range failed { 2344 a = append(a, k) 2345 } 2346 sort.Strings(a) 2347 for _, v := range a { 2348 t.Logf("FAIL %s", v) 2349 } 2350 } 2351 2352 func TestGCCExecuteIEEE(t *testing.T) { 2353 const root = "/github.com/gcc-mirror/gcc/gcc/testsuite/gcc.c-torture/execute/ieee" 2354 g := newGolden(t, fmt.Sprintf("testdata/gcc_ieee_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 2355 2356 defer g.close() 2357 2358 mustEmptyDir(t, tempDir, keep) 2359 wd, err := os.Getwd() 2360 if err != nil { 2361 t.Fatal(err) 2362 } 2363 2364 if err := os.Chdir(tempDir); err != nil { 2365 t.Fatal(err) 2366 } 2367 2368 defer func() { 2369 if err := os.Chdir(wd); err != nil { 2370 t.Fatal(err) 2371 } 2372 }() 2373 2374 blacklist := map[string]struct{}{ 2375 "compare-fp-1.c": {}, //TODO 2376 "compare-fp-4.c": {}, //TODO 2377 "copysign1.c": {}, //TODO 2378 "copysign2.c": {}, //TODO 2379 "fp-cmp-4.c": {}, //TODO 2380 "fp-cmp-4f.c": {}, //TODO 2381 "fp-cmp-4l.c": {}, //TODO 2382 "fp-cmp-5.c": {}, //TODO 2383 "fp-cmp-8.c": {}, //TODO 2384 "fp-cmp-8f.c": {}, //TODO 2385 "fp-cmp-8l.c": {}, //TODO 2386 "inf-1.c": {}, //TODO 2387 "inf-3.c": {}, //TODO 2388 "mzero4.c": {}, //TODO 2389 "pr36332.c": {}, //TODO 2390 "pr38016.c": {}, //TODO 2391 "pr50310.c": {}, //TODO 2392 "pr72824-2.c": {}, //TODO 2393 } 2394 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 2395 case "linux/386": 2396 blacklist["rbug.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 2397 case "freebsd/386": 2398 blacklist["rbug.c"] = struct{}{} //TODO Go1.18 https://github.com/golang/go/issues/48807 2399 case "linux/arm": 2400 blacklist["compare-fp-3.c"] = struct{}{} //TODO 2401 blacklist["rbug.c"] = struct{}{} //TODO 2402 case "linux/s390x": 2403 blacklist["compare-fp-3.c"] = struct{}{} //TODO 2404 case "windows/amd64": 2405 blacklist["fp-cmp-1.c"] = struct{}{} //TODO 2406 blacklist["fp-cmp-2.c"] = struct{}{} //TODO 2407 blacklist["fp-cmp-3.c"] = struct{}{} //TODO 2408 case "windows/arm64": 2409 blacklist["fp-cmp-1.c"] = struct{}{} //TODO 2410 blacklist["fp-cmp-2.c"] = struct{}{} //TODO 2411 blacklist["fp-cmp-3.c"] = struct{}{} //TODO 2412 blacklist["fp-cmp-7.c"] = struct{}{} //TODO 2413 case "windows/386": 2414 blacklist["fp-cmp-1.c"] = struct{}{} //TODO 2415 blacklist["fp-cmp-2.c"] = struct{}{} //TODO 2416 blacklist["fp-cmp-3.c"] = struct{}{} //TODO 2417 blacklist["rbug.c"] = struct{}{} //TODO 2418 case "netbsd/amd64": 2419 blacklist["compare-fp-3.c"] = struct{}{} //TODO 2420 blacklist["fp-cmp-7.c"] = struct{}{} //TODO 2421 case "openbsd/amd64": 2422 blacklist["fp-cmp-7.c"] = struct{}{} //TODO 2423 case "freebsd/arm": 2424 blacklist["fp-cmp-7.c"] = struct{}{} //TODO 2425 } 2426 binary := map[string]bool{} 2427 var rq, res, ok int 2428 limit := runtime.GOMAXPROCS(0) 2429 limiter := make(chan struct{}, limit) 2430 success := make([]string, 0, 0) 2431 results := make(chan *runResult, limit) 2432 failed := map[string]struct{}{} 2433 err = walk(root, func(pth string, fi os.FileInfo) error { 2434 if !strings.HasSuffix(pth, ".c") { 2435 return nil 2436 } 2437 2438 switch { 2439 case re != nil: 2440 if !re.MatchString(pth) { 2441 return nil 2442 } 2443 default: 2444 if _, ok := blacklist[filepath.Base(pth)]; ok { 2445 return nil 2446 } 2447 } 2448 2449 more: 2450 select { 2451 case r := <-results: 2452 res++ 2453 <-limiter 2454 switch r.err.(type) { 2455 case nil: 2456 ok++ 2457 success = append(success, filepath.Base(r.name)) 2458 delete(failed, r.name) 2459 case skipErr: 2460 delete(failed, r.name) 2461 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2462 default: 2463 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2464 } 2465 goto more 2466 case limiter <- struct{}{}: 2467 rq++ 2468 if *oTrace { 2469 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 2470 } 2471 failed[pth] = struct{}{} 2472 go run(pth, binary[filepath.Base(pth)], true, false, results) 2473 } 2474 return nil 2475 }) 2476 if err != nil { 2477 t.Fatal(err) 2478 } 2479 for res != rq { 2480 r := <-results 2481 res++ 2482 <-limiter 2483 switch r.err.(type) { 2484 case nil: 2485 ok++ 2486 success = append(success, filepath.Base(r.name)) 2487 delete(failed, r.name) 2488 case skipErr: 2489 delete(failed, r.name) 2490 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2491 default: 2492 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2493 } 2494 } 2495 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 2496 sort.Strings(success) 2497 for _, fpath := range success { 2498 g.w.Write([]byte(fpath)) 2499 g.w.Write([]byte{'\n'}) 2500 } 2501 if len(failed) == 0 { 2502 return 2503 } 2504 2505 var a []string 2506 for k := range failed { 2507 a = append(a, k) 2508 } 2509 sort.Strings(a) 2510 for _, v := range a { 2511 t.Logf("FAIL %s", v) 2512 } 2513 } 2514 2515 func TestCxgo(t *testing.T) { 2516 const root = "/github.com/cxgo" 2517 g := newGolden(t, fmt.Sprintf("testdata/cxgo_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 2518 2519 defer g.close() 2520 2521 mustEmptyDir(t, tempDir, keep) 2522 wd, err := os.Getwd() 2523 if err != nil { 2524 t.Fatal(err) 2525 } 2526 2527 if err := os.Chdir(tempDir); err != nil { 2528 t.Fatal(err) 2529 } 2530 2531 defer func() { 2532 if err := os.Chdir(wd); err != nil { 2533 t.Fatal(err) 2534 } 2535 }() 2536 2537 needFiles(t, root, []string{}) 2538 blacklist := map[string]struct{}{ 2539 "inet.c": {}, //TODO 2540 "math.c": {}, //TODO 2541 } 2542 var rq, res, ok int 2543 limit := runtime.GOMAXPROCS(0) 2544 limiter := make(chan struct{}, limit) 2545 success := make([]string, 0, 0) 2546 results := make(chan *runResult, limit) 2547 failed := map[string]struct{}{} 2548 err = walk(root, func(pth string, fi os.FileInfo) error { 2549 if !strings.HasSuffix(pth, ".c") { 2550 return nil 2551 } 2552 2553 switch { 2554 case re != nil: 2555 if !re.MatchString(pth) { 2556 return nil 2557 } 2558 default: 2559 if _, ok := blacklist[filepath.Base(pth)]; ok { 2560 return nil 2561 } 2562 } 2563 2564 more: 2565 select { 2566 case r := <-results: 2567 res++ 2568 <-limiter 2569 switch r.err.(type) { 2570 case nil: 2571 ok++ 2572 success = append(success, filepath.Base(r.name)) 2573 delete(failed, r.name) 2574 case skipErr: 2575 delete(failed, r.name) 2576 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2577 default: 2578 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2579 } 2580 goto more 2581 case limiter <- struct{}{}: 2582 rq++ 2583 if *oTrace { 2584 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 2585 } 2586 failed[pth] = struct{}{} 2587 go run(pth, false, false, true, results) 2588 } 2589 return nil 2590 }) 2591 if err != nil { 2592 t.Fatal(err) 2593 } 2594 for res != rq { 2595 r := <-results 2596 res++ 2597 <-limiter 2598 switch r.err.(type) { 2599 case nil: 2600 ok++ 2601 success = append(success, filepath.Base(r.name)) 2602 delete(failed, r.name) 2603 case skipErr: 2604 delete(failed, r.name) 2605 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2606 default: 2607 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2608 } 2609 } 2610 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 2611 sort.Strings(success) 2612 for _, fpath := range success { 2613 g.w.Write([]byte(fpath)) 2614 g.w.Write([]byte{'\n'}) 2615 } 2616 if len(failed) == 0 { 2617 return 2618 } 2619 2620 var a []string 2621 for k := range failed { 2622 a = append(a, k) 2623 } 2624 sort.Strings(a) 2625 for _, v := range a { 2626 t.Logf("FAIL %s", v) 2627 } 2628 } 2629 2630 func TestSQLite(t *testing.T) { 2631 root := filepath.Join(testWD, filepath.FromSlash(sqliteDir)) 2632 testSQLite(t, root) 2633 } 2634 2635 func testSQLite(t *testing.T, dir string) { 2636 const main = "main.go" 2637 wd, err := os.Getwd() 2638 if err != nil { 2639 t.Fatal(err) 2640 } 2641 2642 defer os.Chdir(wd) 2643 2644 temp, err := ioutil.TempDir("", "ccgo-test-") 2645 if err != nil { 2646 t.Fatal(err) 2647 } 2648 2649 switch { 2650 case *oKeep: 2651 t.Log(temp) 2652 default: 2653 defer os.RemoveAll(temp) 2654 } 2655 2656 if _, _, err := CopyDir(temp, dir, nil); err != nil { 2657 t.Fatal(err) 2658 } 2659 2660 if err := os.Chdir(temp); err != nil { 2661 t.Fatal(err) 2662 } 2663 2664 ccgoArgs := []string{ 2665 "ccgo", 2666 2667 "-DHAVE_USLEEP", 2668 "-DLONGDOUBLE_TYPE=double", 2669 "-DSQLITE_DEBUG", 2670 "-DSQLITE_DEFAULT_MEMSTATUS=0", 2671 "-DSQLITE_ENABLE_DBPAGE_VTAB", 2672 "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", 2673 "-DSQLITE_MEMDEBUG", 2674 "-DSQLITE_THREADSAFE=0", 2675 "-D__attribute__(x)=", // bypass parser bug on windows/386 2676 "-export-fields", "F", 2677 "-ignore-unsupported-alignment", 2678 "-all-errors", 2679 "-err-trace", 2680 "-o", main, 2681 "-verify-structs", 2682 "shell.c", 2683 "sqlite3.c", 2684 } 2685 if runtime.GOARCH == "riscv64" { 2686 ccgoArgs = []string{ 2687 "ccgo", 2688 2689 "-DHAVE_USLEEP", 2690 "-DLONGDOUBLE_TYPE=double", 2691 "-DSQLITE_DEBUG", 2692 "-DSQLITE_DEFAULT_MEMSTATUS=0", 2693 "-DSQLITE_ENABLE_DBPAGE_VTAB", 2694 "-DSQLITE_LIKE_DOESNT_MATCH_BLOBS", 2695 "-DSQLITE_MEMDEBUG", 2696 "-DSQLITE_THREADSAFE=0", 2697 "-D__attribute__(x)=", // bypass parser bug on windows/386 2698 "-export-fields", "F", 2699 "-ignore-unsupported-alignment", 2700 "-all-errors", 2701 "-err-trace", 2702 "-o", main, 2703 //TODO "-verify-structs", 2704 "shell.c", 2705 "sqlite3.c", 2706 } 2707 } 2708 if *oDebug { 2709 ccgoArgs = append(ccgoArgs, "-DSQLITE_DEBUG_OS_TRACE", "-DSQLITE_FORCE_OS_TRACE", "-DSQLITE_LOCK_TRACE") 2710 } 2711 if os.Getenv("GO111MODULE") != "off" { 2712 if out, err := Shell("go", "mod", "init", "example.com/ccgo/v3/lib/sqlite"); err != nil { 2713 t.Fatalf("%v\n%s", err, out) 2714 } 2715 2716 if out, err := Shell("go", "get", "modernc.org/libc"); err != nil { 2717 t.Fatalf("%v\n%s", err, out) 2718 } 2719 } 2720 2721 if !func() (r bool) { 2722 defer func() { 2723 if err := recover(); err != nil { 2724 if *oStackTrace { 2725 fmt.Printf("%s\n", stack()) 2726 } 2727 if *oTrace { 2728 fmt.Println(err) 2729 } 2730 t.Errorf("%v", err) 2731 r = false 2732 } 2733 if *oTraceF { 2734 b, _ := ioutil.ReadFile(main) 2735 fmt.Printf("\n----\n%s\n----\n", b) 2736 } 2737 }() 2738 2739 if err := NewTask(ccgoArgs, nil, nil).Main(); err != nil { 2740 if *oTrace { 2741 fmt.Println(err) 2742 } 2743 err = cpp(*oCpp, ccgoArgs, err) 2744 t.Errorf("%v", err) 2745 return false 2746 } 2747 2748 return true 2749 }() { 2750 return 2751 } 2752 2753 shell := "./shell" 2754 if runtime.GOOS == "windows" { 2755 shell = "./shell.exe" 2756 } 2757 args := []string{"build"} 2758 if s := *oXTags; s != "" { 2759 args = append(args, "-tags", s) 2760 } 2761 args = append(args, "-o", shell, main) 2762 if out, err := exec.Command("go", args...).CombinedOutput(); err != nil { 2763 s := strings.TrimSpace(string(out)) 2764 if s != "" { 2765 s += "\n" 2766 } 2767 t.Errorf("%s%v", s, err) 2768 return 2769 } 2770 2771 var out []byte 2772 switch { 2773 case *oDebug: 2774 out, err = exec.Command(shell, "tmp", ".log stdout", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput() 2775 default: 2776 out, err = exec.Command(shell, "tmp", "create table t(i); insert into t values(42); select 11*i from t;").CombinedOutput() 2777 } 2778 if err != nil { 2779 if *oTrace { 2780 fmt.Printf("%s\n%s\n", out, err) 2781 } 2782 t.Errorf("%s\n%v", out, err) 2783 return 2784 } 2785 2786 if g, e := strings.TrimSpace(string(out)), "462"; g != e { 2787 t.Errorf("got: %s\nexp: %s", g, e) 2788 } 2789 if *oTraceO { 2790 fmt.Printf("%s\n", out) 2791 } 2792 2793 if out, err = exec.Command(shell, "tmp", "select 13*i from t;").CombinedOutput(); err != nil { 2794 if *oTrace { 2795 fmt.Printf("%s\n%s\n", out, err) 2796 } 2797 t.Errorf("%v", err) 2798 return 2799 } 2800 2801 if g, e := strings.TrimSpace(string(out)), "546"; g != e { 2802 t.Errorf("got: %s\nexp: %s", g, e) 2803 } 2804 if *oTraceO { 2805 fmt.Printf("%s\n", out) 2806 } 2807 } 2808 2809 func TestBug(t *testing.T) { 2810 const root = "/ccgo/bug" 2811 g := newGolden(t, fmt.Sprintf("testdata/bug_%s_%s.golden", runtime.GOOS, runtime.GOARCH)) 2812 2813 defer g.close() 2814 2815 mustEmptyDir(t, tempDir, keep) 2816 wd, err := os.Getwd() 2817 if err != nil { 2818 t.Fatal(err) 2819 } 2820 2821 if err := os.Chdir(tempDir); err != nil { 2822 t.Fatal(err) 2823 } 2824 2825 defer func() { 2826 if err := os.Chdir(wd); err != nil { 2827 t.Fatal(err) 2828 } 2829 }() 2830 2831 blacklist := map[string]struct{}{} 2832 switch fmt.Sprintf("%s/%s", runtime.GOOS, runtime.GOARCH) { 2833 case "linux/s390x": 2834 blacklist["bitfield.c"] = struct{}{} //TODO 2835 } 2836 var rq, res, ok int 2837 limit := runtime.GOMAXPROCS(0) 2838 limiter := make(chan struct{}, limit) 2839 success := make([]string, 0, 0) 2840 results := make(chan *runResult, limit) 2841 failed := map[string]struct{}{} 2842 err = walk(root, func(pth string, fi os.FileInfo) error { 2843 if !strings.HasSuffix(pth, ".c") { 2844 return nil 2845 } 2846 2847 switch { 2848 case re != nil: 2849 if !re.MatchString(pth) { 2850 return nil 2851 } 2852 default: 2853 if _, ok := blacklist[filepath.Base(pth)]; ok { 2854 return nil 2855 } 2856 } 2857 2858 more: 2859 select { 2860 case r := <-results: 2861 res++ 2862 <-limiter 2863 switch r.err.(type) { 2864 case nil: 2865 ok++ 2866 success = append(success, filepath.Base(r.name)) 2867 delete(failed, r.name) 2868 case skipErr: 2869 delete(failed, r.name) 2870 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2871 default: 2872 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2873 } 2874 goto more 2875 case limiter <- struct{}{}: 2876 rq++ 2877 if *oTrace { 2878 fmt.Fprintf(os.Stderr, "%v: %s\n", rq, pth) 2879 } 2880 failed[pth] = struct{}{} 2881 go run(pth, false, false, false, results) 2882 } 2883 return nil 2884 }) 2885 if err != nil { 2886 t.Fatal(err) 2887 } 2888 for res != rq { 2889 r := <-results 2890 res++ 2891 <-limiter 2892 switch r.err.(type) { 2893 case nil: 2894 ok++ 2895 success = append(success, filepath.Base(r.name)) 2896 delete(failed, r.name) 2897 case skipErr: 2898 delete(failed, r.name) 2899 t.Logf("%v: %v\n%s", r.name, r.err, r.out) 2900 default: 2901 t.Errorf("%v: %v\n%s", r.name, r.err, r.out) 2902 } 2903 } 2904 t.Logf("files %v, ok %v, failed %v", rq, ok, len(failed)) 2905 sort.Strings(success) 2906 for _, fpath := range success { 2907 g.w.Write([]byte(fpath)) 2908 g.w.Write([]byte{'\n'}) 2909 } 2910 if len(failed) == 0 { 2911 return 2912 } 2913 2914 var a []string 2915 for k := range failed { 2916 a = append(a, k) 2917 } 2918 sort.Strings(a) 2919 for _, v := range a { 2920 t.Logf("FAIL %s", v) 2921 } 2922 } 2923 2924 func TestCSmith(t *testing.T) { 2925 gcc := os.Getenv("CC") 2926 if gcc == "" { 2927 gcc = "gcc" 2928 } 2929 gcc, err := exec.LookPath(gcc) 2930 if err != nil { 2931 t.Skip(err) 2932 return 2933 } 2934 2935 if testing.Short() { 2936 t.Skip("skipped: -short") 2937 } 2938 2939 csmith, err := exec.LookPath("csmith") 2940 if err != nil { 2941 t.Skip(err) 2942 return 2943 } 2944 binaryName := filepath.FromSlash("./a.out") 2945 mainName := filepath.FromSlash("main.go") 2946 wd, err := os.Getwd() 2947 if err != nil { 2948 t.Fatal(err) 2949 } 2950 2951 defer os.Chdir(wd) 2952 2953 temp, err := ioutil.TempDir("", "ccgo-test-") 2954 if err != nil { 2955 t.Fatal(err) 2956 } 2957 2958 defer os.RemoveAll(temp) 2959 2960 if err := os.Chdir(temp); err != nil { 2961 t.Fatal(err) 2962 } 2963 2964 if os.Getenv("GO111MODULE") != "off" { 2965 if out, err := Shell("go", "mod", "init", "example.com/ccgo/v3/lib/csmith"); err != nil { 2966 t.Fatalf("%v\n%s", err, out) 2967 } 2968 2969 if out, err := Shell("go", "get", "modernc.org/libc"); err != nil { 2970 t.Fatalf("%v\n%s", err, out) 2971 } 2972 } 2973 2974 fixedBugs := []string{ 2975 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1906742816", 2976 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 612971101", 2977 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 3629008936", 2978 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4130344133", 2979 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3130410542", 2980 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1833258637", 2981 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3126091077", 2982 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324", 2983 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3043990076", 2984 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2517344771", 2985 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 56498550", 2986 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3645367888", 2987 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 169375684", 2988 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3578720023", 2989 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 1885311141", 2990 "--no-bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3720922579", 2991 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 241244373", 2992 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 517639208", 2993 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2205128324", 2994 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2876930815", 2995 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3365074920", 2996 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3329111231", 2997 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2648215054", 2998 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3919255949", 2999 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 890611563", 3000 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4101947480", 3001 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4058772172", 3002 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 2273393378", 3003 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3100949894", 3004 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 15739796933983044010", //TODO fails on linux/s390x 3005 3006 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 963985971", 3007 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 3363122597", 3008 "--bitfields --max-nested-struct-level 10 --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid -s 4146870674", 3009 "--bitfields --no-const-pointers --no-consts --no-packed-struct --no-volatile-pointers --no-volatiles --paranoid --max-nested-struct-level 10 -s 1236173074", //TODO fails on darwin/amd64 3010 } 3011 ch := time.After(*oCSmith) 3012 t0 := time.Now() 3013 var files, ok int 3014 var size int64 3015 var re *regexp.Regexp 3016 if s := *oRE; s != "" { 3017 re = regexp.MustCompile(s) 3018 } 3019 out: 3020 for i := 0; ; i++ { 3021 extra := "" 3022 var args string 3023 switch { 3024 case i < len(fixedBugs): 3025 if re != nil && !re.MatchString(fixedBugs[i]) { 3026 continue 3027 } 3028 3029 args += fixedBugs[i] 3030 a := strings.Split(fixedBugs[i], " ") 3031 extra = strings.Join(a[len(a)-2:], " ") 3032 t.Log(args) 3033 default: 3034 select { 3035 case <-ch: 3036 break out 3037 default: 3038 } 3039 3040 args += csmithDefaultArgs 3041 } 3042 csOut, err := exec.Command(csmith, strings.Split(args, " ")...).Output() 3043 if err != nil { 3044 t.Fatalf("%v\n%s", err, csOut) 3045 } 3046 3047 if fn := *oBlackBox; fn != "" { 3048 if err := ioutil.WriteFile(fn, csOut, 0660); err != nil { 3049 t.Fatal(err) 3050 } 3051 } 3052 3053 if err := ioutil.WriteFile("main.c", csOut, 0660); err != nil { 3054 t.Fatal(err) 3055 } 3056 3057 csp := fmt.Sprintf("-I%s", filepath.FromSlash("/usr/include/csmith")) 3058 if s := os.Getenv("CSMITH_PATH"); s != "" { 3059 csp = fmt.Sprintf("-I%s", s) 3060 } 3061 3062 ccOut, err := exec.Command(gcc, "-o", binaryName, "main.c", csp).CombinedOutput() 3063 if err != nil { 3064 t.Logf("%s\n%s\ncc: %v", extra, ccOut, err) 3065 continue 3066 } 3067 3068 binOutA, err := func() ([]byte, error) { 3069 ctx, cancel := context.WithTimeout(context.Background(), execTimeout) 3070 defer cancel() 3071 3072 return exec.CommandContext(ctx, binaryName).CombinedOutput() 3073 }() 3074 if err != nil { 3075 continue 3076 } 3077 3078 size += int64(len(csOut)) 3079 3080 if err := os.Remove(binaryName); err != nil { 3081 t.Fatal(err) 3082 } 3083 3084 files++ 3085 var stdout, stderr bytes.Buffer 3086 j := NewTask([]string{ 3087 "ccgo", 3088 3089 "-o", mainName, 3090 "-verify-structs", 3091 "main.c", 3092 csp, 3093 }, &stdout, &stderr) 3094 j.cfg.MaxSourceLine = 1 << 20 3095 3096 func() { 3097 3098 defer func() { 3099 if err := recover(); err != nil { 3100 t.Errorf("%s\n%s\nccgo: %s\n%s\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes(), debug.Stack()) 3101 t.Fatal(err) 3102 } 3103 }() 3104 3105 if err := j.Main(); err != nil || stdout.Len() != 0 { 3106 t.Errorf("%s\n%s\nccgo: %s\n%s", extra, csOut, stdout.Bytes(), stderr.Bytes()) 3107 t.Fatal(err) 3108 } 3109 }() 3110 3111 binOutB, err := func() ([]byte, error) { 3112 ctx, cancel := context.WithTimeout(context.Background(), execTimeout) 3113 defer cancel() 3114 3115 return exec.CommandContext(ctx, "go", "run", "-tags=libc.memgrind", mainName).CombinedOutput() 3116 }() 3117 if err != nil { 3118 t.Errorf("%s\n%s\n%s\nccgo: %v", extra, csOut, binOutB, err) 3119 break 3120 } 3121 3122 if g, e := binOutB, binOutA; !bytes.Equal(g, e) { 3123 t.Errorf("%s\n%s\nccgo: %v\ngot: %s\nexp: %s", extra, csOut, err, g, e) 3124 break 3125 } 3126 3127 ok++ 3128 if *oTrace { 3129 fmt.Fprintln(os.Stderr, time.Since(t0), files, ok) 3130 } 3131 3132 if err := os.Remove(mainName); err != nil { 3133 t.Fatal(err) 3134 } 3135 } 3136 d := time.Since(t0) 3137 t.Logf("files %v, bytes %v, ok %v in %v", h(files), h(size), h(ok), d) 3138 } 3139 3140 func dumpInitializer(s []*cc.Initializer) string { 3141 if len(s) == 0 { 3142 return "<empty>" 3143 } 3144 var a []string 3145 for _, v := range s { 3146 var s string 3147 if f := v.Field; f != nil { 3148 s = fmt.Sprintf("fld %q bitfield %v bitoff %2d", f.Name(), f.IsBitField(), f.BitFieldOffset()) 3149 } 3150 a = append(a, fmt.Sprintf("%v: off %#04x val %v %s", v.Position(), v.Offset, v.AssignmentExpression.Operand.Value(), s)) 3151 } 3152 return strings.Join(a, "\n") 3153 }