]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/dist/test.go
runtime: add address sanitizer support for ppc64le
[gostls13.git] / src / cmd / dist / test.go
1 // Copyright 2015 The Go 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 main
6
7 import (
8         "bytes"
9         "flag"
10         "fmt"
11         "io/ioutil"
12         "log"
13         "os"
14         "os/exec"
15         "path"
16         "path/filepath"
17         "reflect"
18         "regexp"
19         "runtime"
20         "strconv"
21         "strings"
22         "sync"
23         "time"
24 )
25
26 func cmdtest() {
27         gogcflags = os.Getenv("GO_GCFLAGS")
28         setNoOpt()
29
30         var t tester
31
32         var noRebuild bool
33         flag.BoolVar(&t.listMode, "list", false, "list available tests")
34         flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
35         flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
36         flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
37         flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
38         flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them. This is for some builders. Not all dist tests respect this flag, but most do.")
39         flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
40         flag.StringVar(&t.runRxStr, "run", os.Getenv("GOTESTONLY"),
41                 "run only those tests matching the regular expression; empty means to run all. "+
42                         "Special exception: if the string begins with '!', the match is inverted.")
43         flag.BoolVar(&t.msan, "msan", false, "run in memory sanitizer builder mode")
44         flag.BoolVar(&t.asan, "asan", false, "run in address sanitizer builder mode")
45
46         xflagparse(-1) // any number of args
47         if noRebuild {
48                 t.rebuild = false
49         }
50
51         t.run()
52 }
53
54 // tester executes cmdtest.
55 type tester struct {
56         race        bool
57         msan        bool
58         asan        bool
59         listMode    bool
60         rebuild     bool
61         failed      bool
62         keepGoing   bool
63         compileOnly bool // just try to compile all tests, but no need to run
64         runRxStr    string
65         runRx       *regexp.Regexp
66         runRxWant   bool     // want runRx to match (true) or not match (false)
67         runNames    []string // tests to run, exclusive with runRx; empty means all
68         banner      string   // prefix, or "" for none
69         lastHeading string   // last dir heading printed
70
71         cgoEnabled bool
72         partial    bool
73         haveTime   bool // the 'time' binary is available
74
75         tests        []distTest
76         timeoutScale int
77
78         worklist []*work
79 }
80
81 type work struct {
82         dt    *distTest
83         cmd   *exec.Cmd
84         start chan bool
85         out   []byte
86         err   error
87         end   chan bool
88 }
89
90 // A distTest is a test run by dist test.
91 // Each test has a unique name and belongs to a group (heading)
92 type distTest struct {
93         name    string // unique test name; may be filtered with -run flag
94         heading string // group section; this header is printed before the test is run.
95         fn      func(*distTest) error
96 }
97
98 func (t *tester) run() {
99         timelog("start", "dist test")
100
101         os.Setenv("PATH", fmt.Sprintf("%s%c%s", gorootBin, os.PathListSeparator, os.Getenv("PATH")))
102
103         cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED")
104         cmd.Stderr = new(bytes.Buffer)
105         slurp, err := cmd.Output()
106         if err != nil {
107                 fatalf("Error running go env CGO_ENABLED: %v\n%s", err, cmd.Stderr)
108         }
109         t.cgoEnabled, _ = strconv.ParseBool(strings.TrimSpace(string(slurp)))
110         if flag.NArg() > 0 && t.runRxStr != "" {
111                 fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
112         }
113
114         t.runNames = flag.Args()
115
116         if t.hasBash() {
117                 if _, err := exec.LookPath("time"); err == nil {
118                         t.haveTime = true
119                 }
120         }
121
122         // Set GOTRACEBACK to system if the user didn't set a level explicitly.
123         // Since we're running tests for Go, we want as much detail as possible
124         // if something goes wrong.
125         //
126         // Set it before running any commands just in case something goes wrong.
127         if ok := isEnvSet("GOTRACEBACK"); !ok {
128                 if err := os.Setenv("GOTRACEBACK", "system"); err != nil {
129                         if t.keepGoing {
130                                 log.Printf("Failed to set GOTRACEBACK: %v", err)
131                         } else {
132                                 fatalf("Failed to set GOTRACEBACK: %v", err)
133                         }
134                 }
135         }
136
137         if t.rebuild {
138                 t.out("Building packages and commands.")
139                 // Force rebuild the whole toolchain.
140                 goInstall("go", append([]string{"-a", "-i"}, toolchain...)...)
141         }
142
143         if !t.listMode {
144                 if os.Getenv("GO_BUILDER_NAME") == "" {
145                         // Complete rebuild bootstrap, even with -no-rebuild.
146                         // If everything is up-to-date, this is a no-op.
147                         // If everything is not up-to-date, the first checkNotStale
148                         // during the test process will kill the tests, so we might
149                         // as well install the world.
150                         // Now that for example "go install cmd/compile" does not
151                         // also install runtime (you need "go install -i cmd/compile"
152                         // for that), it's easy for previous workflows like
153                         // "rebuild the compiler and then run run.bash"
154                         // to break if we don't automatically refresh things here.
155                         // Rebuilding is a shortened bootstrap.
156                         // See cmdbootstrap for a description of the overall process.
157                         goInstall("go", append([]string{"-i"}, toolchain...)...)
158                         goInstall("go", append([]string{"-i"}, toolchain...)...)
159                         goInstall("go", "std", "cmd")
160                 } else {
161                         // The Go builder infrastructure should always begin running tests from a
162                         // clean, non-stale state, so there is no need to rebuild the world.
163                         // Instead, we can just check that it is not stale, which may be less
164                         // expensive (and is also more likely to catch bugs in the builder
165                         // implementation).
166                         willTest := []string{"std"}
167                         if t.shouldTestCmd() {
168                                 willTest = append(willTest, "cmd")
169                         }
170                         checkNotStale("go", willTest...)
171                 }
172         }
173
174         t.timeoutScale = 1
175         switch goarch {
176         case "arm":
177                 t.timeoutScale = 2
178         case "mips", "mipsle", "mips64", "mips64le":
179                 t.timeoutScale = 4
180         }
181         if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
182                 t.timeoutScale, err = strconv.Atoi(s)
183                 if err != nil {
184                         fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
185                 }
186         }
187
188         if t.runRxStr != "" {
189                 if t.runRxStr[0] == '!' {
190                         t.runRxWant = false
191                         t.runRxStr = t.runRxStr[1:]
192                 } else {
193                         t.runRxWant = true
194                 }
195                 t.runRx = regexp.MustCompile(t.runRxStr)
196         }
197
198         t.registerTests()
199         if t.listMode {
200                 for _, tt := range t.tests {
201                         fmt.Println(tt.name)
202                 }
203                 return
204         }
205
206         for _, name := range t.runNames {
207                 if !t.isRegisteredTestName(name) {
208                         fatalf("unknown test %q", name)
209                 }
210         }
211
212         // On a few builders, make GOROOT unwritable to catch tests writing to it.
213         if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
214                 if os.Getuid() == 0 {
215                         // Don't bother making GOROOT unwritable:
216                         // we're running as root, so permissions would have no effect.
217                 } else {
218                         xatexit(t.makeGOROOTUnwritable())
219                 }
220         }
221
222         if err := t.maybeLogMetadata(); err != nil {
223                 t.failed = true
224                 if t.keepGoing {
225                         log.Printf("Failed logging metadata: %v", err)
226                 } else {
227                         fatalf("Failed logging metadata: %v", err)
228                 }
229         }
230
231         for _, dt := range t.tests {
232                 if !t.shouldRunTest(dt.name) {
233                         t.partial = true
234                         continue
235                 }
236                 dt := dt // dt used in background after this iteration
237                 if err := dt.fn(&dt); err != nil {
238                         t.runPending(&dt) // in case that hasn't been done yet
239                         t.failed = true
240                         if t.keepGoing {
241                                 log.Printf("Failed: %v", err)
242                         } else {
243                                 fatalf("Failed: %v", err)
244                         }
245                 }
246         }
247         t.runPending(nil)
248         timelog("end", "dist test")
249
250         if t.failed {
251                 fmt.Println("\nFAILED")
252                 xexit(1)
253         } else if incomplete[goos+"/"+goarch] {
254                 // The test succeeded, but consider it as failed so we don't
255                 // forget to remove the port from the incomplete map once the
256                 // port is complete.
257                 fmt.Println("\nFAILED (incomplete port)")
258                 xexit(1)
259         } else if t.partial {
260                 fmt.Println("\nALL TESTS PASSED (some were excluded)")
261         } else {
262                 fmt.Println("\nALL TESTS PASSED")
263         }
264 }
265
266 func (t *tester) shouldRunTest(name string) bool {
267         if t.runRx != nil {
268                 return t.runRx.MatchString(name) == t.runRxWant
269         }
270         if len(t.runNames) == 0 {
271                 return true
272         }
273         for _, runName := range t.runNames {
274                 if runName == name {
275                         return true
276                 }
277         }
278         return false
279 }
280
281 func (t *tester) maybeLogMetadata() error {
282         if t.compileOnly {
283                 // We need to run a subprocess to log metadata. Don't do that
284                 // on compile-only runs.
285                 return nil
286         }
287         t.out("Test execution environment.")
288         // Helper binary to print system metadata (CPU model, etc). This is a
289         // separate binary from dist so it need not build with the bootstrap
290         // toolchain.
291         //
292         // TODO(prattmic): If we split dist bootstrap and dist test then this
293         // could be simplified to directly use internal/sysinfo here.
294         return t.dirCmd(filepath.Join(goroot, "src/cmd/internal/metadata"), "go", []string{"run", "main.go"}).Run()
295 }
296
297 // short returns a -short flag value to use with 'go test'
298 // or a test binary for tests intended to run in short mode.
299 // It returns "true", unless the environment variable
300 // GO_TEST_SHORT is set to a non-empty, false-ish string.
301 //
302 // This environment variable is meant to be an internal
303 // detail between the Go build system and cmd/dist for
304 // the purpose of longtest builders, and is not intended
305 // for use by users. See golang.org/issue/12508.
306 func short() string {
307         if v := os.Getenv("GO_TEST_SHORT"); v != "" {
308                 short, err := strconv.ParseBool(v)
309                 if err != nil {
310                         fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
311                 }
312                 if !short {
313                         return "false"
314                 }
315         }
316         return "true"
317 }
318
319 // goTest returns the beginning of the go test command line.
320 // Callers should use goTest and then pass flags overriding these
321 // defaults as later arguments in the command line.
322 func (t *tester) goTest() []string {
323         return []string{
324                 "go", "test", "-short=" + short(), "-count=1", t.tags(), t.runFlag(""),
325         }
326 }
327
328 func (t *tester) tags() string {
329         ios := t.iOS()
330         switch {
331         case ios && noOpt:
332                 return "-tags=lldb,noopt"
333         case ios:
334                 return "-tags=lldb"
335         case noOpt:
336                 return "-tags=noopt"
337         default:
338                 return "-tags="
339         }
340 }
341
342 // timeoutDuration converts the provided number of seconds into a
343 // time.Duration, scaled by the t.timeoutScale factor.
344 func (t *tester) timeoutDuration(sec int) time.Duration {
345         return time.Duration(sec) * time.Second * time.Duration(t.timeoutScale)
346 }
347
348 // timeout returns the "-timeout=" string argument to "go test" given
349 // the number of seconds of timeout. It scales it by the
350 // t.timeoutScale factor.
351 func (t *tester) timeout(sec int) string {
352         return "-timeout=" + t.timeoutDuration(sec).String()
353 }
354
355 // ranGoTest and stdMatches are state closed over by the stdlib
356 // testing func in registerStdTest below. The tests are run
357 // sequentially, so there's no need for locks.
358 //
359 // ranGoBench and benchMatches are the same, but are only used
360 // in -race mode.
361 var (
362         ranGoTest  bool
363         stdMatches []string
364
365         ranGoBench   bool
366         benchMatches []string
367 )
368
369 func (t *tester) registerStdTest(pkg string) {
370         heading := "Testing packages."
371         testPrefix := "go_test:"
372         gcflags := gogcflags
373
374         testName := testPrefix + pkg
375         if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
376                 stdMatches = append(stdMatches, pkg)
377         }
378
379         t.tests = append(t.tests, distTest{
380                 name:    testName,
381                 heading: heading,
382                 fn: func(dt *distTest) error {
383                         if ranGoTest {
384                                 return nil
385                         }
386                         t.runPending(dt)
387                         timelog("start", dt.name)
388                         defer timelog("end", dt.name)
389                         ranGoTest = true
390
391                         timeoutSec := 180
392                         for _, pkg := range stdMatches {
393                                 if pkg == "cmd/go" {
394                                         timeoutSec *= 3
395                                         break
396                                 }
397                         }
398                         // Special case for our slow cross-compiled
399                         // qemu builders:
400                         if t.shouldUsePrecompiledStdTest() {
401                                 return t.runPrecompiledStdTest(t.timeoutDuration(timeoutSec))
402                         }
403                         args := []string{
404                                 "test",
405                                 "-short=" + short(),
406                                 t.tags(),
407                                 t.timeout(timeoutSec),
408                         }
409                         if gcflags != "" {
410                                 args = append(args, "-gcflags=all="+gcflags)
411                         }
412                         if t.race {
413                                 args = append(args, "-race")
414                         }
415                         if t.msan {
416                                 args = append(args, "-msan")
417                         }
418                         if t.asan {
419                                 args = append(args, "-asan")
420                         }
421                         if t.compileOnly {
422                                 args = append(args, "-run=^$")
423                         }
424                         args = append(args, stdMatches...)
425                         cmd := exec.Command(gorootBinGo, args...)
426                         cmd.Stdout = os.Stdout
427                         cmd.Stderr = os.Stderr
428                         return cmd.Run()
429                 },
430         })
431 }
432
433 func (t *tester) registerRaceBenchTest(pkg string) {
434         testName := "go_test_bench:" + pkg
435         if t.runRx == nil || t.runRx.MatchString(testName) == t.runRxWant {
436                 benchMatches = append(benchMatches, pkg)
437         }
438         t.tests = append(t.tests, distTest{
439                 name:    testName,
440                 heading: "Running benchmarks briefly.",
441                 fn: func(dt *distTest) error {
442                         if ranGoBench {
443                                 return nil
444                         }
445                         t.runPending(dt)
446                         timelog("start", dt.name)
447                         defer timelog("end", dt.name)
448                         ranGoBench = true
449                         args := []string{
450                                 "test",
451                                 "-short=" + short(),
452                                 "-race",
453                                 t.timeout(1200), // longer timeout for race with benchmarks
454                                 "-run=^$",       // nothing. only benchmarks.
455                                 "-benchtime=.1s",
456                                 "-cpu=4",
457                         }
458                         if !t.compileOnly {
459                                 args = append(args, "-bench=.*")
460                         }
461                         args = append(args, benchMatches...)
462                         cmd := exec.Command(gorootBinGo, args...)
463                         cmd.Stdout = os.Stdout
464                         cmd.Stderr = os.Stderr
465                         return cmd.Run()
466                 },
467         })
468 }
469
470 // stdOutErrAreTerminals is defined in test_linux.go, to report
471 // whether stdout & stderr are terminals.
472 var stdOutErrAreTerminals func() bool
473
474 func (t *tester) registerTests() {
475         // Fast path to avoid the ~1 second of `go list std cmd` when
476         // the caller lists specific tests to run. (as the continuous
477         // build coordinator does).
478         if len(t.runNames) > 0 {
479                 for _, name := range t.runNames {
480                         if strings.HasPrefix(name, "go_test:") {
481                                 t.registerStdTest(strings.TrimPrefix(name, "go_test:"))
482                         }
483                         if strings.HasPrefix(name, "go_test_bench:") {
484                                 t.registerRaceBenchTest(strings.TrimPrefix(name, "go_test_bench:"))
485                         }
486                 }
487         } else {
488                 // Use a format string to only list packages and commands that have tests.
489                 const format = "{{if (or .TestGoFiles .XTestGoFiles)}}{{.ImportPath}}{{end}}"
490                 cmd := exec.Command(gorootBinGo, "list", "-f", format)
491                 if t.race {
492                         cmd.Args = append(cmd.Args, "-tags=race")
493                 }
494                 cmd.Args = append(cmd.Args, "std")
495                 if t.shouldTestCmd() {
496                         cmd.Args = append(cmd.Args, "cmd")
497                 }
498                 cmd.Stderr = new(bytes.Buffer)
499                 all, err := cmd.Output()
500                 if err != nil {
501                         fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
502                 }
503                 pkgs := strings.Fields(string(all))
504                 for _, pkg := range pkgs {
505                         t.registerStdTest(pkg)
506                 }
507                 if t.race {
508                         for _, pkg := range pkgs {
509                                 if t.packageHasBenchmarks(pkg) {
510                                         t.registerRaceBenchTest(pkg)
511                                 }
512                         }
513                 }
514         }
515
516         // Test the os/user package in the pure-Go mode too.
517         if !t.compileOnly {
518                 t.tests = append(t.tests, distTest{
519                         name:    "osusergo",
520                         heading: "os/user with tag osusergo",
521                         fn: func(dt *distTest) error {
522                                 t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-tags=osusergo", "os/user")
523                                 return nil
524                         },
525                 })
526         }
527
528         // Test ios/amd64 for the iOS simulator.
529         if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
530                 t.tests = append(t.tests, distTest{
531                         name:    "amd64ios",
532                         heading: "GOOS=ios on darwin/amd64",
533                         fn: func(dt *distTest) error {
534                                 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(300), "-run=SystemRoots", "crypto/x509")
535                                 setEnv(cmd, "GOOS", "ios")
536                                 setEnv(cmd, "CGO_ENABLED", "1")
537                                 return nil
538                         },
539                 })
540         }
541
542         if t.race {
543                 return
544         }
545
546         // Runtime CPU tests.
547         if !t.compileOnly && goos != "js" { // js can't handle -cpu != 1
548                 testName := "runtime:cpu124"
549                 t.tests = append(t.tests, distTest{
550                         name:    testName,
551                         heading: "GOMAXPROCS=2 runtime -cpu=1,2,4 -quick",
552                         fn: func(dt *distTest) error {
553                                 cmd := t.addCmd(dt, "src", t.goTest(), "-short=true", t.timeout(300), "runtime", "-cpu=1,2,4", "-quick")
554                                 // We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
555                                 // creation of first goroutines and first garbage collections in the parallel setting.
556                                 setEnv(cmd, "GOMAXPROCS", "2")
557                                 return nil
558                         },
559                 })
560         }
561
562         // morestack tests. We only run these on in long-test mode
563         // (with GO_TEST_SHORT=false) because the runtime test is
564         // already quite long and mayMoreStackMove makes it about
565         // twice as slow.
566         if !t.compileOnly && short() == "false" {
567                 // hooks is the set of maymorestack hooks to test with.
568                 hooks := []string{"mayMoreStackPreempt", "mayMoreStackMove"}
569                 // pkgs is the set of test packages to run.
570                 pkgs := []string{"runtime", "reflect", "sync"}
571                 // hookPkgs is the set of package patterns to apply
572                 // the maymorestack hook to.
573                 hookPkgs := []string{"runtime/...", "reflect", "sync"}
574                 // unhookPkgs is the set of package patterns to
575                 // exclude from hookPkgs.
576                 unhookPkgs := []string{"runtime/testdata/..."}
577                 for _, hook := range hooks {
578                         // Construct the build flags to use the
579                         // maymorestack hook in the compiler and
580                         // assembler. We pass this via the GOFLAGS
581                         // environment variable so that it applies to
582                         // both the test itself and to binaries built
583                         // by the test.
584                         goFlagsList := []string{}
585                         for _, flag := range []string{"-gcflags", "-asmflags"} {
586                                 for _, hookPkg := range hookPkgs {
587                                         goFlagsList = append(goFlagsList, flag+"="+hookPkg+"=-d=maymorestack=runtime."+hook)
588                                 }
589                                 for _, unhookPkg := range unhookPkgs {
590                                         goFlagsList = append(goFlagsList, flag+"="+unhookPkg+"=")
591                                 }
592                         }
593                         goFlags := strings.Join(goFlagsList, " ")
594
595                         for _, pkg := range pkgs {
596                                 pkg := pkg
597                                 testName := hook + ":" + pkg
598                                 t.tests = append(t.tests, distTest{
599                                         name:    testName,
600                                         heading: "maymorestack=" + hook,
601                                         fn: func(dt *distTest) error {
602                                                 cmd := t.addCmd(dt, "src", t.goTest(), t.timeout(600), pkg, "-short")
603                                                 setEnv(cmd, "GOFLAGS", goFlags)
604                                                 return nil
605                                         },
606                                 })
607                         }
608                 }
609         }
610
611         // This test needs its stdout/stderr to be terminals, so we don't run it from cmd/go's tests.
612         // See issue 18153.
613         if goos == "linux" {
614                 t.tests = append(t.tests, distTest{
615                         name:    "cmd_go_test_terminal",
616                         heading: "cmd/go terminal test",
617                         fn: func(dt *distTest) error {
618                                 t.runPending(dt)
619                                 timelog("start", dt.name)
620                                 defer timelog("end", dt.name)
621                                 if !stdOutErrAreTerminals() {
622                                         fmt.Println("skipping terminal test; stdout/stderr not terminals")
623                                         return nil
624                                 }
625                                 cmd := exec.Command(gorootBinGo, "test")
626                                 setDir(cmd, filepath.Join(os.Getenv("GOROOT"), "src/cmd/go/testdata/testterminal18153"))
627                                 cmd.Stdout = os.Stdout
628                                 cmd.Stderr = os.Stderr
629                                 return cmd.Run()
630                         },
631                 })
632         }
633
634         // On the builders only, test that a moved GOROOT still works.
635         // Fails on iOS because CC_FOR_TARGET refers to clangwrap.sh
636         // in the unmoved GOROOT.
637         // Fails on Android and js/wasm with an exec format error.
638         // Fails on plan9 with "cannot find GOROOT" (issue #21016).
639         if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() && goos != "plan9" && goos != "js" {
640                 t.tests = append(t.tests, distTest{
641                         name:    "moved_goroot",
642                         heading: "moved GOROOT",
643                         fn: func(dt *distTest) error {
644                                 t.runPending(dt)
645                                 timelog("start", dt.name)
646                                 defer timelog("end", dt.name)
647                                 moved := goroot + "-moved"
648                                 if err := os.Rename(goroot, moved); err != nil {
649                                         if goos == "windows" {
650                                                 // Fails on Windows (with "Access is denied") if a process
651                                                 // or binary is in this directory. For instance, using all.bat
652                                                 // when run from c:\workdir\go\src fails here
653                                                 // if GO_BUILDER_NAME is set. Our builders invoke tests
654                                                 // a different way which happens to work when sharding
655                                                 // tests, but we should be tolerant of the non-sharded
656                                                 // all.bat case.
657                                                 log.Printf("skipping test on Windows")
658                                                 return nil
659                                         }
660                                         return err
661                                 }
662
663                                 // Run `go test fmt` in the moved GOROOT, without explicitly setting
664                                 // GOROOT in the environment. The 'go' command should find itself.
665                                 cmd := exec.Command(filepath.Join(moved, "bin", "go"), "test", "fmt")
666                                 cmd.Stdout = os.Stdout
667                                 cmd.Stderr = os.Stderr
668                                 unsetEnv(cmd, "GOROOT")
669                                 unsetEnv(cmd, "GOCACHE") // TODO(bcmills): ...why‽
670                                 err := cmd.Run()
671
672                                 if rerr := os.Rename(moved, goroot); rerr != nil {
673                                         fatalf("failed to restore GOROOT: %v", rerr)
674                                 }
675                                 return err
676                         },
677                 })
678         }
679
680         // Test that internal linking of standard packages does not
681         // require libgcc. This ensures that we can install a Go
682         // release on a system that does not have a C compiler
683         // installed and still build Go programs (that don't use cgo).
684         for _, pkg := range cgoPackages {
685                 if !t.internalLink() {
686                         break
687                 }
688
689                 // ARM libgcc may be Thumb, which internal linking does not support.
690                 if goarch == "arm" {
691                         break
692                 }
693
694                 pkg := pkg
695                 var run string
696                 if pkg == "net" {
697                         run = "TestTCPStress"
698                 }
699                 t.tests = append(t.tests, distTest{
700                         name:    "nolibgcc:" + pkg,
701                         heading: "Testing without libgcc.",
702                         fn: func(dt *distTest) error {
703                                 // What matters is that the tests build and start up.
704                                 // Skip expensive tests, especially x509 TestSystemRoots.
705                                 t.addCmd(dt, "src", t.goTest(), "-ldflags=-linkmode=internal -libgcc=none", "-run=^Test[^CS]", pkg, t.runFlag(run))
706                                 return nil
707                         },
708                 })
709         }
710
711         // Stub out following test on alpine until 54354 resolved.
712         builderName := os.Getenv("GO_BUILDER_NAME")
713         disablePIE := strings.HasSuffix(builderName, "-alpine")
714
715         // Test internal linking of PIE binaries where it is supported.
716         if t.internalLinkPIE() && !disablePIE {
717                 t.tests = append(t.tests, distTest{
718                         name:    "pie_internal",
719                         heading: "internal linking of -buildmode=pie",
720                         fn: func(dt *distTest) error {
721                                 t.addCmd(dt, "src", t.goTest(), "reflect", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
722                                 return nil
723                         },
724                 })
725                 // Also test a cgo package.
726                 if t.cgoEnabled && t.internalLink() && !disablePIE {
727                         t.tests = append(t.tests, distTest{
728                                 name:    "pie_internal_cgo",
729                                 heading: "internal linking of -buildmode=pie",
730                                 fn: func(dt *distTest) error {
731                                         t.addCmd(dt, "src", t.goTest(), "os/user", "-buildmode=pie", "-ldflags=-linkmode=internal", t.timeout(60))
732                                         return nil
733                                 },
734                         })
735                 }
736         }
737
738         // sync tests
739         if goos != "js" { // js doesn't support -cpu=10
740                 t.tests = append(t.tests, distTest{
741                         name:    "sync_cpu",
742                         heading: "sync -cpu=10",
743                         fn: func(dt *distTest) error {
744                                 t.addCmd(dt, "src", t.goTest(), "sync", t.timeout(120), "-cpu=10", t.runFlag(""))
745                                 return nil
746                         },
747                 })
748         }
749
750         if t.raceDetectorSupported() {
751                 t.tests = append(t.tests, distTest{
752                         name:    "race",
753                         heading: "Testing race detector",
754                         fn:      t.raceTest,
755                 })
756         }
757
758         if t.cgoEnabled && !t.iOS() {
759                 // Disabled on iOS. golang.org/issue/15919
760                 t.registerHostTest("cgo_stdio", "../misc/cgo/stdio", "misc/cgo/stdio", ".")
761                 t.registerHostTest("cgo_life", "../misc/cgo/life", "misc/cgo/life", ".")
762                 fortran := os.Getenv("FC")
763                 if fortran == "" {
764                         fortran, _ = exec.LookPath("gfortran")
765                 }
766                 if t.hasBash() && goos != "android" && fortran != "" {
767                         t.tests = append(t.tests, distTest{
768                                 name:    "cgo_fortran",
769                                 heading: "../misc/cgo/fortran",
770                                 fn: func(dt *distTest) error {
771                                         t.addCmd(dt, "misc/cgo/fortran", "./test.bash", fortran)
772                                         return nil
773                                 },
774                         })
775                 }
776                 if t.hasSwig() && goos != "android" {
777                         t.tests = append(t.tests, distTest{
778                                 name:    "swig_stdio",
779                                 heading: "../misc/swig/stdio",
780                                 fn: func(dt *distTest) error {
781                                         t.addCmd(dt, "misc/swig/stdio", t.goTest(), ".")
782                                         return nil
783                                 },
784                         })
785                         if t.hasCxx() {
786                                 t.tests = append(t.tests,
787                                         distTest{
788                                                 name:    "swig_callback",
789                                                 heading: "../misc/swig/callback",
790                                                 fn: func(dt *distTest) error {
791                                                         t.addCmd(dt, "misc/swig/callback", t.goTest(), ".")
792                                                         return nil
793                                                 },
794                                         },
795                                         distTest{
796                                                 name:    "swig_callback_lto",
797                                                 heading: "../misc/swig/callback",
798                                                 fn: func(dt *distTest) error {
799                                                         cmd := t.addCmd(dt, "misc/swig/callback", t.goTest(), ".")
800                                                         setEnv(cmd, "CGO_CFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
801                                                         setEnv(cmd, "CGO_CXXFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
802                                                         setEnv(cmd, "CGO_LDFLAGS", "-flto -Wno-lto-type-mismatch -Wno-unknown-warning-option")
803                                                         return nil
804                                                 },
805                                         },
806                                 )
807                         }
808                 }
809         }
810         if t.cgoEnabled {
811                 t.tests = append(t.tests, distTest{
812                         name:    "cgo_test",
813                         heading: "../misc/cgo/test",
814                         fn:      t.cgoTest,
815                 })
816         }
817
818         // Don't run these tests with $GO_GCFLAGS because most of them
819         // assume that they can run "go install" with no -gcflags and not
820         // recompile the entire standard library. If make.bash ran with
821         // special -gcflags, that's not true.
822         if t.cgoEnabled && gogcflags == "" {
823                 t.registerHostTest("testgodefs", "../misc/cgo/testgodefs", "misc/cgo/testgodefs", ".")
824
825                 t.registerTest("testso", "../misc/cgo/testso", t.goTest(), t.timeout(600), ".")
826                 t.registerTest("testsovar", "../misc/cgo/testsovar", t.goTest(), t.timeout(600), ".")
827                 if t.supportedBuildmode("c-archive") {
828                         t.registerHostTest("testcarchive", "../misc/cgo/testcarchive", "misc/cgo/testcarchive", ".")
829                 }
830                 if t.supportedBuildmode("c-shared") {
831                         t.registerHostTest("testcshared", "../misc/cgo/testcshared", "misc/cgo/testcshared", ".")
832                 }
833                 if t.supportedBuildmode("shared") {
834                         t.registerTest("testshared", "../misc/cgo/testshared", t.goTest(), t.timeout(600), ".")
835                 }
836                 if t.supportedBuildmode("plugin") {
837                         t.registerTest("testplugin", "../misc/cgo/testplugin", t.goTest(), t.timeout(600), ".")
838                 }
839                 if gohostos == "linux" && (goarch == "amd64" || goarch == "ppc64le") {
840                         t.registerTest("testasan", "../misc/cgo/testasan", "go", "run", ".")
841                 }
842                 if goos == "linux" {
843                         // because syscall.SysProcAttr struct used in misc/cgo/testsanitizers is only built on linux.
844                         t.registerHostTest("testsanitizers", "../misc/cgo/testsanitizers", "misc/cgo/testsanitizers", ".")
845                 }
846                 if t.hasBash() && goos != "android" && !t.iOS() && gohostos != "windows" {
847                         t.registerHostTest("cgo_errors", "../misc/cgo/errors", "misc/cgo/errors", ".")
848                 }
849                 if gohostos == "linux" && t.extLink() {
850                         t.registerTest("testsigfwd", "../misc/cgo/testsigfwd", "go", "run", ".")
851                 }
852         }
853
854         if goos != "android" && !t.iOS() {
855                 // There are no tests in this directory, only benchmarks.
856                 // Check that the test binary builds but don't bother running it.
857                 // (It has init-time work to set up for the benchmarks that is not worth doing unnecessarily.)
858                 t.registerTest("bench_go1", "../test/bench/go1", t.goTest(), "-c", "-o="+os.DevNull)
859         }
860         if goos != "android" && !t.iOS() {
861                 // Only start multiple test dir shards on builders,
862                 // where they get distributed to multiple machines.
863                 // See issues 20141 and 31834.
864                 nShards := 1
865                 if os.Getenv("GO_BUILDER_NAME") != "" {
866                         nShards = 10
867                 }
868                 if n, err := strconv.Atoi(os.Getenv("GO_TEST_SHARDS")); err == nil {
869                         nShards = n
870                 }
871                 for shard := 0; shard < nShards; shard++ {
872                         shard := shard
873                         t.tests = append(t.tests, distTest{
874                                 name:    fmt.Sprintf("test:%d_%d", shard, nShards),
875                                 heading: "../test",
876                                 fn:      func(dt *distTest) error { return t.testDirTest(dt, shard, nShards) },
877                         })
878                 }
879         }
880         // Only run the API check on fast development platforms.
881         // Every platform checks the API on every GOOS/GOARCH/CGO_ENABLED combination anyway,
882         // so we really only need to run this check once anywhere to get adequate coverage.
883         // To help developers avoid trybot-only failures, we try to run on typical developer machines
884         // which is darwin/linux/windows and amd64/arm64.
885         if (goos == "darwin" || goos == "linux" || goos == "windows") && (goarch == "amd64" || goarch == "arm64") {
886                 t.tests = append(t.tests, distTest{
887                         name:    "api",
888                         heading: "API check",
889                         fn: func(dt *distTest) error {
890                                 if t.compileOnly {
891                                         t.addCmd(dt, "src", "go", "build", "-o", os.DevNull, filepath.Join(goroot, "src/cmd/api/run.go"))
892                                         return nil
893                                 }
894                                 t.addCmd(dt, "src", "go", "run", filepath.Join(goroot, "src/cmd/api/run.go"))
895                                 return nil
896                         },
897                 })
898         }
899
900         // Ensure that the toolchain can bootstrap itself.
901         // This test adds another ~45s to all.bash if run sequentially, so run it only on the builders.
902         if os.Getenv("GO_BUILDER_NAME") != "" && goos != "android" && !t.iOS() {
903                 t.registerHostTest("reboot", "../misc/reboot", "misc/reboot", ".")
904         }
905 }
906
907 // isRegisteredTestName reports whether a test named testName has already
908 // been registered.
909 func (t *tester) isRegisteredTestName(testName string) bool {
910         for _, tt := range t.tests {
911                 if tt.name == testName {
912                         return true
913                 }
914         }
915         return false
916 }
917
918 func (t *tester) registerTest1(seq bool, name, dirBanner string, cmdline ...interface{}) {
919         bin, args := flattenCmdline(cmdline)
920         if bin == "time" && !t.haveTime {
921                 bin, args = args[0], args[1:]
922         }
923         if t.isRegisteredTestName(name) {
924                 panic("duplicate registered test name " + name)
925         }
926         t.tests = append(t.tests, distTest{
927                 name:    name,
928                 heading: dirBanner,
929                 fn: func(dt *distTest) error {
930                         if seq {
931                                 t.runPending(dt)
932                                 timelog("start", name)
933                                 defer timelog("end", name)
934                                 return t.dirCmd(filepath.Join(goroot, "src", dirBanner), bin, args).Run()
935                         }
936                         t.addCmd(dt, filepath.Join(goroot, "src", dirBanner), bin, args)
937                         return nil
938                 },
939         })
940 }
941
942 func (t *tester) registerTest(name, dirBanner string, cmdline ...interface{}) {
943         t.registerTest1(false, name, dirBanner, cmdline...)
944 }
945
946 func (t *tester) registerSeqTest(name, dirBanner string, cmdline ...interface{}) {
947         t.registerTest1(true, name, dirBanner, cmdline...)
948 }
949
950 func (t *tester) bgDirCmd(dir, bin string, args ...string) *exec.Cmd {
951         cmd := exec.Command(bin, args...)
952         if filepath.IsAbs(dir) {
953                 setDir(cmd, dir)
954         } else {
955                 setDir(cmd, filepath.Join(goroot, dir))
956         }
957         return cmd
958 }
959
960 func (t *tester) dirCmd(dir string, cmdline ...interface{}) *exec.Cmd {
961         bin, args := flattenCmdline(cmdline)
962         cmd := t.bgDirCmd(dir, bin, args...)
963         cmd.Stdout = os.Stdout
964         cmd.Stderr = os.Stderr
965         if vflag > 1 {
966                 errprintf("%s\n", strings.Join(cmd.Args, " "))
967         }
968         return cmd
969 }
970
971 // flattenCmdline flattens a mixture of string and []string as single list
972 // and then interprets it as a command line: first element is binary, then args.
973 func flattenCmdline(cmdline []interface{}) (bin string, args []string) {
974         var list []string
975         for _, x := range cmdline {
976                 switch x := x.(type) {
977                 case string:
978                         list = append(list, x)
979                 case []string:
980                         list = append(list, x...)
981                 default:
982                         panic("invalid addCmd argument type: " + reflect.TypeOf(x).String())
983                 }
984         }
985
986         // The go command is too picky about duplicated flags.
987         // Drop all but the last of the allowed duplicated flags.
988         drop := make([]bool, len(list))
989         have := map[string]int{}
990         for i := 1; i < len(list); i++ {
991                 j := strings.Index(list[i], "=")
992                 if j < 0 {
993                         continue
994                 }
995                 flag := list[i][:j]
996                 switch flag {
997                 case "-run", "-tags":
998                         if have[flag] != 0 {
999                                 drop[have[flag]] = true
1000                         }
1001                         have[flag] = i
1002                 }
1003         }
1004         out := list[:0]
1005         for i, x := range list {
1006                 if !drop[i] {
1007                         out = append(out, x)
1008                 }
1009         }
1010         list = out
1011
1012         bin = list[0]
1013         if bin == "go" {
1014                 bin = gorootBinGo
1015         }
1016         return bin, list[1:]
1017 }
1018
1019 func (t *tester) addCmd(dt *distTest, dir string, cmdline ...interface{}) *exec.Cmd {
1020         bin, args := flattenCmdline(cmdline)
1021         w := &work{
1022                 dt:  dt,
1023                 cmd: t.bgDirCmd(dir, bin, args...),
1024         }
1025         t.worklist = append(t.worklist, w)
1026         return w.cmd
1027 }
1028
1029 func (t *tester) iOS() bool {
1030         return goos == "ios"
1031 }
1032
1033 func (t *tester) out(v string) {
1034         if t.banner == "" {
1035                 return
1036         }
1037         fmt.Println("\n" + t.banner + v)
1038 }
1039
1040 func (t *tester) extLink() bool {
1041         pair := gohostos + "-" + goarch
1042         switch pair {
1043         case "aix-ppc64",
1044                 "android-arm", "android-arm64",
1045                 "darwin-amd64", "darwin-arm64",
1046                 "dragonfly-amd64",
1047                 "freebsd-386", "freebsd-amd64", "freebsd-arm",
1048                 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-loong64", "linux-ppc64le", "linux-mips64", "linux-mips64le", "linux-mips", "linux-mipsle", "linux-riscv64", "linux-s390x",
1049                 "netbsd-386", "netbsd-amd64",
1050                 "openbsd-386", "openbsd-amd64",
1051                 "windows-386", "windows-amd64":
1052                 return true
1053         }
1054         return false
1055 }
1056
1057 func (t *tester) internalLink() bool {
1058         if gohostos == "dragonfly" {
1059                 // linkmode=internal fails on dragonfly since errno is a TLS relocation.
1060                 return false
1061         }
1062         if goos == "android" {
1063                 return false
1064         }
1065         if goos == "ios" {
1066                 return false
1067         }
1068         if goos == "windows" && goarch == "arm64" {
1069                 return false
1070         }
1071         // Internally linking cgo is incomplete on some architectures.
1072         // https://golang.org/issue/10373
1073         // https://golang.org/issue/14449
1074         if goarch == "loong64" || goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" {
1075                 return false
1076         }
1077         if goos == "aix" {
1078                 // linkmode=internal isn't supported.
1079                 return false
1080         }
1081         return true
1082 }
1083
1084 func (t *tester) internalLinkPIE() bool {
1085         switch goos + "-" + goarch {
1086         case "darwin-amd64", "darwin-arm64",
1087                 "linux-amd64", "linux-arm64", "linux-ppc64le",
1088                 "android-arm64",
1089                 "windows-amd64", "windows-386", "windows-arm":
1090                 return true
1091         }
1092         return false
1093 }
1094
1095 func (t *tester) supportedBuildmode(mode string) bool {
1096         pair := goos + "-" + goarch
1097         switch mode {
1098         case "c-archive":
1099                 if !t.extLink() {
1100                         return false
1101                 }
1102                 switch pair {
1103                 case "aix-ppc64",
1104                         "darwin-amd64", "darwin-arm64", "ios-arm64",
1105                         "linux-amd64", "linux-386", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1106                         "freebsd-amd64",
1107                         "windows-amd64", "windows-386":
1108                         return true
1109                 }
1110                 return false
1111         case "c-shared":
1112                 switch pair {
1113                 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1114                         "darwin-amd64", "darwin-arm64",
1115                         "freebsd-amd64",
1116                         "android-arm", "android-arm64", "android-386",
1117                         "windows-amd64", "windows-386", "windows-arm64":
1118                         return true
1119                 }
1120                 return false
1121         case "shared":
1122                 switch pair {
1123                 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-s390x":
1124                         return true
1125                 }
1126                 return false
1127         case "plugin":
1128                 switch pair {
1129                 case "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-s390x", "linux-ppc64le":
1130                         return true
1131                 case "darwin-amd64", "darwin-arm64":
1132                         return true
1133                 case "freebsd-amd64":
1134                         return true
1135                 }
1136                 return false
1137         case "pie":
1138                 switch pair {
1139                 case "aix/ppc64",
1140                         "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1141                         "android-amd64", "android-arm", "android-arm64", "android-386":
1142                         return true
1143                 case "darwin-amd64", "darwin-arm64":
1144                         return true
1145                 case "windows-amd64", "windows-386", "windows-arm":
1146                         return true
1147                 }
1148                 return false
1149
1150         default:
1151                 fatalf("internal error: unknown buildmode %s", mode)
1152                 return false
1153         }
1154 }
1155
1156 func (t *tester) registerHostTest(name, heading, dir, pkg string) {
1157         t.tests = append(t.tests, distTest{
1158                 name:    name,
1159                 heading: heading,
1160                 fn: func(dt *distTest) error {
1161                         t.runPending(dt)
1162                         timelog("start", name)
1163                         defer timelog("end", name)
1164                         return t.runHostTest(dir, pkg)
1165                 },
1166         })
1167 }
1168
1169 func (t *tester) runHostTest(dir, pkg string) error {
1170         out, err := exec.Command(gorootBinGo, "env", "GOEXE", "GOTMPDIR").Output()
1171         if err != nil {
1172                 return err
1173         }
1174
1175         parts := strings.Split(string(out), "\n")
1176         if len(parts) < 2 {
1177                 return fmt.Errorf("'go env GOEXE GOTMPDIR' output contains <2 lines")
1178         }
1179         GOEXE := strings.TrimSpace(parts[0])
1180         GOTMPDIR := strings.TrimSpace(parts[1])
1181
1182         f, err := ioutil.TempFile(GOTMPDIR, "test.test-*"+GOEXE)
1183         if err != nil {
1184                 return err
1185         }
1186         f.Close()
1187         defer os.Remove(f.Name())
1188
1189         cmd := t.dirCmd(dir, t.goTest(), "-c", "-o", f.Name(), pkg)
1190         setEnv(cmd, "GOARCH", gohostarch)
1191         setEnv(cmd, "GOOS", gohostos)
1192         if err := cmd.Run(); err != nil {
1193                 return err
1194         }
1195         return t.dirCmd(dir, f.Name(), "-test.short="+short(), "-test.timeout="+t.timeoutDuration(300).String()).Run()
1196 }
1197
1198 func (t *tester) cgoTest(dt *distTest) error {
1199         cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1200         setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=auto")
1201
1202         // Stub out various buildmode=pie tests  on alpine until 54354 resolved.
1203         builderName := os.Getenv("GO_BUILDER_NAME")
1204         disablePIE := strings.HasSuffix(builderName, "-alpine")
1205
1206         if t.internalLink() {
1207                 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=internal", ".")
1208                 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=internal")
1209         }
1210
1211         pair := gohostos + "-" + goarch
1212         switch pair {
1213         case "darwin-amd64", "darwin-arm64",
1214                 "windows-386", "windows-amd64":
1215                 // test linkmode=external, but __thread not supported, so skip testtls.
1216                 if !t.extLink() {
1217                         break
1218                 }
1219                 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1220                 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1221
1222                 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-ldflags", "-linkmode=external -s", ".")
1223
1224                 if t.supportedBuildmode("pie") && !disablePIE {
1225
1226                         t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", ".")
1227                         if t.internalLink() && t.internalLinkPIE() {
1228                                 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie", ".")
1229                         }
1230                 }
1231
1232         case "aix-ppc64",
1233                 "android-arm", "android-arm64",
1234                 "dragonfly-amd64",
1235                 "freebsd-386", "freebsd-amd64", "freebsd-arm",
1236                 "linux-386", "linux-amd64", "linux-arm", "linux-arm64", "linux-ppc64le", "linux-riscv64", "linux-s390x",
1237                 "netbsd-386", "netbsd-amd64",
1238                 "openbsd-386", "openbsd-amd64", "openbsd-arm", "openbsd-arm64", "openbsd-mips64":
1239
1240                 cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), ".")
1241                 setEnv(cmd, "GOFLAGS", "-ldflags=-linkmode=external")
1242                 // cgo should be able to cope with both -g arguments and colored
1243                 // diagnostics.
1244                 setEnv(cmd, "CGO_CFLAGS", "-g0 -fdiagnostics-color")
1245
1246                 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=auto", ".")
1247                 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", "-linkmode=external", ".")
1248
1249                 switch pair {
1250                 case "aix-ppc64", "netbsd-386", "netbsd-amd64":
1251                         // no static linking
1252                 case "freebsd-arm":
1253                         // -fPIC compiled tls code will use __tls_get_addr instead
1254                         // of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
1255                         // is implemented in rtld-elf, so -fPIC isn't compatible with
1256                         // static linking on FreeBSD/ARM with clang. (cgo depends on
1257                         // -fPIC fundamentally.)
1258                 default:
1259                         cmd := t.dirCmd("misc/cgo/test",
1260                                 compilerEnvLookup(defaultcc, goos, goarch), "-xc", "-o", "/dev/null", "-static", "-")
1261                         cmd.Stdin = strings.NewReader("int main() {}")
1262                         if err := cmd.Run(); err != nil {
1263                                 fmt.Println("No support for static linking found (lacks libc.a?), skip cgo static linking test.")
1264                         } else {
1265                                 if goos != "android" {
1266                                         t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1267                                 }
1268                                 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), ".")
1269                                 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external`, ".")
1270                                 if goos != "android" {
1271                                         t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1272                                         t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", "-ldflags", `-linkmode=external -extldflags "-static -pthread"`, ".")
1273                                         // -static in CGO_LDFLAGS triggers a different code path
1274                                         // than -static in -extldflags, so test both.
1275                                         // See issue #16651.
1276                                         cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-tags=static", ".")
1277                                         setEnv(cmd, "CGO_LDFLAGS", "-static -pthread")
1278                                 }
1279                         }
1280
1281                         if t.supportedBuildmode("pie") && !disablePIE {
1282                                 t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", ".")
1283                                 if t.internalLink() && t.internalLinkPIE() {
1284                                         t.addCmd(dt, "misc/cgo/test", t.goTest(), "-buildmode=pie", "-ldflags=-linkmode=internal", "-tags=internal,internal_pie", ".")
1285                                 }
1286                                 t.addCmd(dt, "misc/cgo/testtls", t.goTest(), "-buildmode=pie", ".")
1287                                 t.addCmd(dt, "misc/cgo/nocgo", t.goTest(), "-buildmode=pie", ".")
1288                         }
1289                 }
1290         }
1291
1292         return nil
1293 }
1294
1295 // run pending test commands, in parallel, emitting headers as appropriate.
1296 // When finished, emit header for nextTest, which is going to run after the
1297 // pending commands are done (and runPending returns).
1298 // A test should call runPending if it wants to make sure that it is not
1299 // running in parallel with earlier tests, or if it has some other reason
1300 // for needing the earlier tests to be done.
1301 func (t *tester) runPending(nextTest *distTest) {
1302         checkNotStale("go", "std")
1303         worklist := t.worklist
1304         t.worklist = nil
1305         for _, w := range worklist {
1306                 w.start = make(chan bool)
1307                 w.end = make(chan bool)
1308                 go func(w *work) {
1309                         if !<-w.start {
1310                                 timelog("skip", w.dt.name)
1311                                 w.out = []byte(fmt.Sprintf("skipped due to earlier error\n"))
1312                         } else {
1313                                 timelog("start", w.dt.name)
1314                                 w.out, w.err = w.cmd.CombinedOutput()
1315                                 if w.err != nil {
1316                                         if isUnsupportedVMASize(w) {
1317                                                 timelog("skip", w.dt.name)
1318                                                 w.out = []byte(fmt.Sprintf("skipped due to unsupported VMA\n"))
1319                                                 w.err = nil
1320                                         }
1321                                 }
1322                         }
1323                         timelog("end", w.dt.name)
1324                         w.end <- true
1325                 }(w)
1326         }
1327
1328         started := 0
1329         ended := 0
1330         var last *distTest
1331         for ended < len(worklist) {
1332                 for started < len(worklist) && started-ended < maxbg {
1333                         w := worklist[started]
1334                         started++
1335                         w.start <- !t.failed || t.keepGoing
1336                 }
1337                 w := worklist[ended]
1338                 dt := w.dt
1339                 if dt.heading != "" && t.lastHeading != dt.heading {
1340                         t.lastHeading = dt.heading
1341                         t.out(dt.heading)
1342                 }
1343                 if dt != last {
1344                         // Assumes all the entries for a single dt are in one worklist.
1345                         last = w.dt
1346                         if vflag > 0 {
1347                                 fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1348                         }
1349                 }
1350                 if vflag > 1 {
1351                         errprintf("%s\n", strings.Join(w.cmd.Args, " "))
1352                 }
1353                 ended++
1354                 <-w.end
1355                 os.Stdout.Write(w.out)
1356                 if w.err != nil {
1357                         log.Printf("Failed: %v", w.err)
1358                         t.failed = true
1359                 }
1360                 checkNotStale("go", "std")
1361         }
1362         if t.failed && !t.keepGoing {
1363                 fatalf("FAILED")
1364         }
1365
1366         if dt := nextTest; dt != nil {
1367                 if dt.heading != "" && t.lastHeading != dt.heading {
1368                         t.lastHeading = dt.heading
1369                         t.out(dt.heading)
1370                 }
1371                 if vflag > 0 {
1372                         fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
1373                 }
1374         }
1375 }
1376
1377 func (t *tester) hasBash() bool {
1378         switch gohostos {
1379         case "windows", "plan9":
1380                 return false
1381         }
1382         return true
1383 }
1384
1385 func (t *tester) hasCxx() bool {
1386         cxx, _ := exec.LookPath(compilerEnvLookup(defaultcxx, goos, goarch))
1387         return cxx != ""
1388 }
1389
1390 func (t *tester) hasSwig() bool {
1391         swig, err := exec.LookPath("swig")
1392         if err != nil {
1393                 return false
1394         }
1395
1396         // Check that swig was installed with Go support by checking
1397         // that a go directory exists inside the swiglib directory.
1398         // See https://golang.org/issue/23469.
1399         output, err := exec.Command(swig, "-go", "-swiglib").Output()
1400         if err != nil {
1401                 return false
1402         }
1403         swigDir := strings.TrimSpace(string(output))
1404
1405         _, err = os.Stat(filepath.Join(swigDir, "go"))
1406         if err != nil {
1407                 return false
1408         }
1409
1410         // Check that swig has a new enough version.
1411         // See https://golang.org/issue/22858.
1412         out, err := exec.Command(swig, "-version").CombinedOutput()
1413         if err != nil {
1414                 return false
1415         }
1416
1417         re := regexp.MustCompile(`[vV]ersion +([\d]+)([.][\d]+)?([.][\d]+)?`)
1418         matches := re.FindSubmatch(out)
1419         if matches == nil {
1420                 // Can't find version number; hope for the best.
1421                 return true
1422         }
1423
1424         major, err := strconv.Atoi(string(matches[1]))
1425         if err != nil {
1426                 // Can't find version number; hope for the best.
1427                 return true
1428         }
1429         if major < 3 {
1430                 return false
1431         }
1432         if major > 3 {
1433                 // 4.0 or later
1434                 return true
1435         }
1436
1437         // We have SWIG version 3.x.
1438         if len(matches[2]) > 0 {
1439                 minor, err := strconv.Atoi(string(matches[2][1:]))
1440                 if err != nil {
1441                         return true
1442                 }
1443                 if minor > 0 {
1444                         // 3.1 or later
1445                         return true
1446                 }
1447         }
1448
1449         // We have SWIG version 3.0.x.
1450         if len(matches[3]) > 0 {
1451                 patch, err := strconv.Atoi(string(matches[3][1:]))
1452                 if err != nil {
1453                         return true
1454                 }
1455                 if patch < 6 {
1456                         // Before 3.0.6.
1457                         return false
1458                 }
1459         }
1460
1461         return true
1462 }
1463
1464 func (t *tester) raceDetectorSupported() bool {
1465         if gohostos != goos {
1466                 return false
1467         }
1468         if !t.cgoEnabled {
1469                 return false
1470         }
1471         if !raceDetectorSupported(goos, goarch) {
1472                 return false
1473         }
1474         // The race detector doesn't work on Alpine Linux:
1475         // golang.org/issue/14481
1476         if isAlpineLinux() {
1477                 return false
1478         }
1479         // NetBSD support is unfinished.
1480         // golang.org/issue/26403
1481         if goos == "netbsd" {
1482                 return false
1483         }
1484         return true
1485 }
1486
1487 func isAlpineLinux() bool {
1488         if runtime.GOOS != "linux" {
1489                 return false
1490         }
1491         fi, err := os.Lstat("/etc/alpine-release")
1492         return err == nil && fi.Mode().IsRegular()
1493 }
1494
1495 func (t *tester) runFlag(rx string) string {
1496         if t.compileOnly {
1497                 return "-run=^$"
1498         }
1499         return "-run=" + rx
1500 }
1501
1502 func (t *tester) raceTest(dt *distTest) error {
1503         t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("Output"), "runtime/race")
1504         t.addCmd(dt, "src", t.goTest(), "-race", t.runFlag("TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace"), "flag", "net", "os", "os/exec", "encoding/gob")
1505         // We don't want the following line, because it
1506         // slows down all.bash (by 10 seconds on my laptop).
1507         // The race builder should catch any error here, but doesn't.
1508         // TODO(iant): Figure out how to catch this.
1509         // t.addCmd(dt, "src", t.goTest(),  "-race", "-run=TestParallelTest", "cmd/go")
1510         if t.cgoEnabled {
1511                 // Building misc/cgo/test takes a long time.
1512                 // There are already cgo-enabled packages being tested with the race detector.
1513                 // We shouldn't need to redo all of misc/cgo/test too.
1514                 // The race buildler will take care of this.
1515                 // cmd := t.addCmd(dt, "misc/cgo/test", t.goTest(), "-race")
1516                 // setEnv(cmd, "GOTRACEBACK", "2")
1517         }
1518         if t.extLink() {
1519                 // Test with external linking; see issue 9133.
1520                 t.addCmd(dt, "src", t.goTest(), "-race", "-ldflags=-linkmode=external", t.runFlag("TestParse|TestEcho|TestStdinCloseRace"), "flag", "os/exec")
1521         }
1522         return nil
1523 }
1524
1525 var runtest struct {
1526         sync.Once
1527         exe string
1528         err error
1529 }
1530
1531 func (t *tester) testDirTest(dt *distTest, shard, shards int) error {
1532         runtest.Do(func() {
1533                 f, err := ioutil.TempFile("", "runtest-*.exe") // named exe for Windows, but harmless elsewhere
1534                 if err != nil {
1535                         runtest.err = err
1536                         return
1537                 }
1538                 f.Close()
1539
1540                 runtest.exe = f.Name()
1541                 xatexit(func() {
1542                         os.Remove(runtest.exe)
1543                 })
1544
1545                 cmd := t.dirCmd("test", "go", "build", "-o", runtest.exe, "run.go")
1546                 setEnv(cmd, "GOOS", gohostos)
1547                 setEnv(cmd, "GOARCH", gohostarch)
1548                 runtest.err = cmd.Run()
1549         })
1550         if runtest.err != nil {
1551                 return runtest.err
1552         }
1553         if t.compileOnly {
1554                 return nil
1555         }
1556         t.addCmd(dt, "test", runtest.exe,
1557                 fmt.Sprintf("--shard=%d", shard),
1558                 fmt.Sprintf("--shards=%d", shards),
1559         )
1560         return nil
1561 }
1562
1563 // cgoPackages is the standard packages that use cgo.
1564 var cgoPackages = []string{
1565         "net",
1566         "os/user",
1567 }
1568
1569 var funcBenchmark = []byte("\nfunc Benchmark")
1570
1571 // packageHasBenchmarks reports whether pkg has benchmarks.
1572 // On any error, it conservatively returns true.
1573 //
1574 // This exists just to eliminate work on the builders, since compiling
1575 // a test in race mode just to discover it has no benchmarks costs a
1576 // second or two per package, and this function returns false for
1577 // about 100 packages.
1578 func (t *tester) packageHasBenchmarks(pkg string) bool {
1579         pkgDir := filepath.Join(goroot, "src", pkg)
1580         d, err := os.Open(pkgDir)
1581         if err != nil {
1582                 return true // conservatively
1583         }
1584         defer d.Close()
1585         names, err := d.Readdirnames(-1)
1586         if err != nil {
1587                 return true // conservatively
1588         }
1589         for _, name := range names {
1590                 if !strings.HasSuffix(name, "_test.go") {
1591                         continue
1592                 }
1593                 slurp, err := ioutil.ReadFile(filepath.Join(pkgDir, name))
1594                 if err != nil {
1595                         return true // conservatively
1596                 }
1597                 if bytes.Contains(slurp, funcBenchmark) {
1598                         return true
1599                 }
1600         }
1601         return false
1602 }
1603
1604 // makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to
1605 // check that no tests accidentally write to $GOROOT.
1606 func (t *tester) makeGOROOTUnwritable() (undo func()) {
1607         dir := os.Getenv("GOROOT")
1608         if dir == "" {
1609                 panic("GOROOT not set")
1610         }
1611
1612         type pathMode struct {
1613                 path string
1614                 mode os.FileMode
1615         }
1616         var dirs []pathMode // in lexical order
1617
1618         undo = func() {
1619                 for i := range dirs {
1620                         os.Chmod(dirs[i].path, dirs[i].mode) // best effort
1621                 }
1622         }
1623
1624         gocache := os.Getenv("GOCACHE")
1625         if gocache == "" {
1626                 panic("GOCACHE not set")
1627         }
1628         gocacheSubdir, _ := filepath.Rel(dir, gocache)
1629
1630         // Note: Can't use WalkDir here, because this has to compile with Go 1.4.
1631         filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
1632                 if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
1633                         if suffix == gocacheSubdir {
1634                                 // Leave GOCACHE writable: we may need to write test binaries into it.
1635                                 return filepath.SkipDir
1636                         }
1637                         if suffix == ".git" {
1638                                 // Leave Git metadata in whatever state it was in. It may contain a lot
1639                                 // of files, and it is highly unlikely that a test will try to modify
1640                                 // anything within that directory.
1641                                 return filepath.SkipDir
1642                         }
1643                 }
1644                 if err == nil {
1645                         mode := info.Mode()
1646                         if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {
1647                                 dirs = append(dirs, pathMode{path, mode})
1648                         }
1649                 }
1650                 return nil
1651         })
1652
1653         // Run over list backward to chmod children before parents.
1654         for i := len(dirs) - 1; i >= 0; i-- {
1655                 err := os.Chmod(dirs[i].path, dirs[i].mode&^0222)
1656                 if err != nil {
1657                         dirs = dirs[i:] // Only undo what we did so far.
1658                         undo()
1659                         fatalf("failed to make GOROOT read-only: %v", err)
1660                 }
1661         }
1662
1663         return undo
1664 }
1665
1666 // shouldUsePrecompiledStdTest reports whether "dist test" should use
1667 // a pre-compiled go test binary on disk rather than running "go test"
1668 // and compiling it again. This is used by our slow qemu-based builder
1669 // that do full processor emulation where we cross-compile the
1670 // make.bash step as well as pre-compile each std test binary.
1671 //
1672 // This only reports true if dist is run with an single go_test:foo
1673 // argument (as the build coordinator does with our slow qemu-based
1674 // builders), we're in a builder environment ("GO_BUILDER_NAME" is set),
1675 // and the pre-built test binary exists.
1676 func (t *tester) shouldUsePrecompiledStdTest() bool {
1677         bin := t.prebuiltGoPackageTestBinary()
1678         if bin == "" {
1679                 return false
1680         }
1681         _, err := os.Stat(bin)
1682         return err == nil
1683 }
1684
1685 func (t *tester) shouldTestCmd() bool {
1686         if goos == "js" && goarch == "wasm" {
1687                 // Issues 25911, 35220
1688                 return false
1689         }
1690         return true
1691 }
1692
1693 // prebuiltGoPackageTestBinary returns the path where we'd expect
1694 // the pre-built go test binary to be on disk when dist test is run with
1695 // a single argument.
1696 // It returns an empty string if a pre-built binary should not be used.
1697 func (t *tester) prebuiltGoPackageTestBinary() string {
1698         if len(stdMatches) != 1 || t.race || t.compileOnly || os.Getenv("GO_BUILDER_NAME") == "" {
1699                 return ""
1700         }
1701         pkg := stdMatches[0]
1702         return filepath.Join(os.Getenv("GOROOT"), "src", pkg, path.Base(pkg)+".test")
1703 }
1704
1705 // runPrecompiledStdTest runs the pre-compiled standard library package test binary.
1706 // See shouldUsePrecompiledStdTest above; it must return true for this to be called.
1707 func (t *tester) runPrecompiledStdTest(timeout time.Duration) error {
1708         bin := t.prebuiltGoPackageTestBinary()
1709         fmt.Fprintf(os.Stderr, "# %s: using pre-built %s...\n", stdMatches[0], bin)
1710         cmd := exec.Command(bin, "-test.short="+short(), "-test.timeout="+timeout.String())
1711         setDir(cmd, filepath.Dir(bin))
1712         cmd.Stdout = os.Stdout
1713         cmd.Stderr = os.Stderr
1714         if err := cmd.Start(); err != nil {
1715                 return err
1716         }
1717         // And start a timer to kill the process if it doesn't kill
1718         // itself in the prescribed timeout.
1719         const backupKillFactor = 1.05 // add 5%
1720         timer := time.AfterFunc(time.Duration(float64(timeout)*backupKillFactor), func() {
1721                 fmt.Fprintf(os.Stderr, "# %s: timeout running %s; killing...\n", stdMatches[0], bin)
1722                 cmd.Process.Kill()
1723         })
1724         defer timer.Stop()
1725         return cmd.Wait()
1726 }
1727
1728 // raceDetectorSupported is a copy of the function
1729 // cmd/internal/sys.RaceDetectorSupported, which can't be used here
1730 // because cmd/dist has to be buildable by Go 1.4.
1731 // The race detector only supports 48-bit VMA on arm64. But we don't have
1732 // a good solution to check VMA size(See https://golang.org/issue/29948)
1733 // raceDetectorSupported will always return true for arm64. But race
1734 // detector tests may abort on non 48-bit VMA configuration, the tests
1735 // will be marked as "skipped" in this case.
1736 func raceDetectorSupported(goos, goarch string) bool {
1737         switch goos {
1738         case "linux":
1739                 return goarch == "amd64" || goarch == "ppc64le" || goarch == "arm64" || goarch == "s390x"
1740         case "darwin":
1741                 return goarch == "amd64" || goarch == "arm64"
1742         case "freebsd", "netbsd", "openbsd", "windows":
1743                 return goarch == "amd64"
1744         default:
1745                 return false
1746         }
1747 }
1748
1749 // isUnsupportedVMASize reports whether the failure is caused by an unsupported
1750 // VMA for the race detector (for example, running the race detector on an
1751 // arm64 machine configured with 39-bit VMA)
1752 func isUnsupportedVMASize(w *work) bool {
1753         unsupportedVMA := []byte("unsupported VMA range")
1754         return w.dt.name == "race" && bytes.Contains(w.out, unsupportedVMA)
1755 }
1756
1757 // isEnvSet reports whether the environment variable evar is
1758 // set in the environment.
1759 func isEnvSet(evar string) bool {
1760         evarEq := evar + "="
1761         for _, e := range os.Environ() {
1762                 if strings.HasPrefix(e, evarEq) {
1763                         return true
1764                 }
1765         }
1766         return false
1767 }