Help us shape the future of Go! Take the 2026 Go Developer Survey

Source file 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  	"encoding/json"
    10  	"flag"
    11  	"fmt"
    12  	"io"
    13  	"io/fs"
    14  	"log"
    15  	"os"
    16  	"os/exec"
    17  	"path/filepath"
    18  	"reflect"
    19  	"regexp"
    20  	"runtime"
    21  	"slices"
    22  	"strconv"
    23  	"strings"
    24  	"time"
    25  )
    26  
    27  func cmdtest() {
    28  	gogcflags = os.Getenv("GO_GCFLAGS")
    29  	setNoOpt()
    30  
    31  	var t tester
    32  
    33  	t.asmflags = os.Getenv("GO_TEST_ASMFLAGS")
    34  
    35  	var noRebuild bool
    36  	flag.BoolVar(&t.listMode, "list", false, "list available tests")
    37  	flag.BoolVar(&t.rebuild, "rebuild", false, "rebuild everything first")
    38  	flag.BoolVar(&noRebuild, "no-rebuild", false, "overrides -rebuild (historical dreg)")
    39  	flag.BoolVar(&t.keepGoing, "k", false, "keep going even when error occurred")
    40  	flag.BoolVar(&t.race, "race", false, "run in race builder mode (different set of tests)")
    41  	flag.BoolVar(&t.compileOnly, "compile-only", false, "compile tests, but don't run them")
    42  	flag.StringVar(&t.banner, "banner", "##### ", "banner prefix; blank means no section banners")
    43  	flag.StringVar(&t.runRxStr, "run", "",
    44  		"run only those tests matching the regular expression; empty means to run all. "+
    45  			"Special exception: if the string begins with '!', the match is inverted.")
    46  	flag.BoolVar(&t.msan, "msan", false, "run in memory sanitizer builder mode")
    47  	flag.BoolVar(&t.asan, "asan", false, "run in address sanitizer builder mode")
    48  	flag.BoolVar(&t.json, "json", false, "report test results in JSON")
    49  	flag.StringVar(&t.artifactsDir, "artifacts-dir", "", "save test artifacts in the specified directory")
    50  	flag.StringVar(&debugTrace, "debug-trace", debugTrace, "write a merged trace of the test run to `file`")
    51  
    52  	xflagparse(-1) // any number of args
    53  	if noRebuild {
    54  		debugTraceAppend = true
    55  		t.rebuild = false
    56  	}
    57  
    58  	t.run()
    59  }
    60  
    61  // tester executes cmdtest.
    62  type tester struct {
    63  	race         bool
    64  	msan         bool
    65  	asan         bool
    66  	listMode     bool
    67  	rebuild      bool
    68  	failed       bool
    69  	keepGoing    bool
    70  	compileOnly  bool // just try to compile all tests, but no need to run
    71  	short        bool
    72  	cgoEnabled   bool
    73  	asmflags     string
    74  	json         bool
    75  	artifactsDir string
    76  	runRxStr     string
    77  	runRx        *regexp.Regexp
    78  	runRxWant    bool     // want runRx to match (true) or not match (false)
    79  	runNames     []string // tests to run, exclusive with runRx; empty means all
    80  	banner       string   // prefix, or "" for none
    81  	lastHeading  string   // last dir heading printed
    82  
    83  	tests        []distTest // use addTest to extend
    84  	testNames    map[string]bool
    85  	timeoutScale int // a non-negative integer factor to scale test timeout by; defaults to 1
    86  
    87  	worklist []*work
    88  }
    89  
    90  // work tracks command execution for a test.
    91  type work struct {
    92  	dt    *distTest     // unique test name, etc.
    93  	cmd   *exec.Cmd     // must write stdout/stderr to out
    94  	flush func()        // if non-nil, called after cmd.Run
    95  	start chan bool     // a true means to start, a false means to skip
    96  	out   bytes.Buffer  // combined stdout/stderr from cmd
    97  	err   error         // work result
    98  	end   chan struct{} // a value means cmd ended (or was skipped)
    99  }
   100  
   101  // printSkip prints a skip message for all of work.
   102  func (w *work) printSkip(t *tester, msg string) {
   103  	if t.json {
   104  		synthesizeSkipEvent(json.NewEncoder(&w.out), w.dt.name, msg)
   105  		return
   106  	}
   107  	fmt.Fprintln(&w.out, msg)
   108  }
   109  
   110  // A distTest is a test run by dist test.
   111  // Each test has a unique name and belongs to a group (heading)
   112  type distTest struct {
   113  	name    string // unique test name; may be filtered with -run flag
   114  	heading string // group section; this header is printed before the test is run.
   115  	fn      func(*distTest) error
   116  }
   117  
   118  func (t *tester) run() {
   119  	timelog("start", "dist test")
   120  	distSpan := startSpan("dist test")
   121  
   122  	os.Setenv("PATH", fmt.Sprintf("%s%c%s", gorootBin, os.PathListSeparator, os.Getenv("PATH")))
   123  
   124  	t.short = true
   125  	if v := os.Getenv("GO_TEST_SHORT"); v != "" {
   126  		short, err := strconv.ParseBool(v)
   127  		if err != nil {
   128  			fatalf("invalid GO_TEST_SHORT %q: %v", v, err)
   129  		}
   130  		t.short = short
   131  	}
   132  
   133  	cmd := exec.Command(gorootBinGo, "env", "CGO_ENABLED")
   134  	cmd.Stderr = new(bytes.Buffer)
   135  	slurp, err := cmd.Output()
   136  	if err != nil {
   137  		fatalf("Error running %s: %v\n%s", cmd, err, cmd.Stderr)
   138  	}
   139  	parts := strings.Split(string(slurp), "\n")
   140  	if nlines := len(parts) - 1; nlines < 1 {
   141  		fatalf("Error running %s: output contains <1 lines\n%s", cmd, cmd.Stderr)
   142  	}
   143  	t.cgoEnabled, _ = strconv.ParseBool(parts[0])
   144  
   145  	if flag.NArg() > 0 && t.runRxStr != "" {
   146  		fatalf("the -run regular expression flag is mutually exclusive with test name arguments")
   147  	}
   148  
   149  	t.runNames = flag.Args()
   150  
   151  	// Set GOTRACEBACK to system if the user didn't set a level explicitly.
   152  	// Since we're running tests for Go, we want as much detail as possible
   153  	// if something goes wrong.
   154  	//
   155  	// Set it before running any commands just in case something goes wrong.
   156  	if ok := isEnvSet("GOTRACEBACK"); !ok {
   157  		if err := os.Setenv("GOTRACEBACK", "system"); err != nil {
   158  			if t.keepGoing {
   159  				log.Printf("Failed to set GOTRACEBACK: %v", err)
   160  			} else {
   161  				fatalf("Failed to set GOTRACEBACK: %v", err)
   162  			}
   163  		}
   164  	}
   165  
   166  	if t.rebuild {
   167  		t.out("Building packages and commands.")
   168  		// Force rebuild the whole toolchain.
   169  		rebuildSpan := startSpan("rebuild toolchain")
   170  		goInstall(toolenv(), gorootBinGo, append(append(maybeTraceFlag("rebuildToolchain"), "-a"), toolchain...)...)
   171  		rebuildSpan.done()
   172  	}
   173  
   174  	if !t.listMode {
   175  		if builder := os.Getenv("GO_BUILDER_NAME"); builder == "" {
   176  			// Ensure that installed commands are up to date, even with -no-rebuild,
   177  			// so that tests that run commands end up testing what's actually on disk.
   178  			// If everything is up-to-date, this is a no-op.
   179  			// We first build the toolchain twice to allow it to converge,
   180  			// as when we first bootstrap.
   181  			// See cmdbootstrap for a description of the overall process.
   182  			//
   183  			// On the builders, we skip this step: we assume that 'dist test' is
   184  			// already using the result of a clean build, and because of test sharding
   185  			// and virtualization we usually start with a clean GOCACHE, so we would
   186  			// end up rebuilding large parts of the standard library that aren't
   187  			// otherwise relevant to the actual set of packages under test.
   188  			toolchain1Span := startSpan("toolchain1")
   189  			goInstall(toolenv(), gorootBinGo, append(maybeTraceFlag("toolchain1"), toolchain...)...)
   190  			toolchain1Span.done()
   191  			toolchain2Span := startSpan("toolchain2")
   192  			goInstall(toolenv(), gorootBinGo, append(maybeTraceFlag("toolchain2"), toolchain...)...)
   193  			toolchain2Span.done()
   194  			toolsSpan := startSpan("tools")
   195  			goInstall(toolenv(), gorootBinGo, append(maybeTraceFlag("tools"), toolsToInstall...)...)
   196  			toolsSpan.done()
   197  		}
   198  	}
   199  
   200  	t.timeoutScale = 1
   201  	if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
   202  		t.timeoutScale, err = strconv.Atoi(s)
   203  		if err != nil {
   204  			fatalf("failed to parse $GO_TEST_TIMEOUT_SCALE = %q as integer: %v", s, err)
   205  		}
   206  	}
   207  
   208  	if t.runRxStr != "" {
   209  		if t.runRxStr[0] == '!' {
   210  			t.runRxWant = false
   211  			t.runRxStr = t.runRxStr[1:]
   212  		} else {
   213  			t.runRxWant = true
   214  		}
   215  		t.runRx = regexp.MustCompile(t.runRxStr)
   216  	}
   217  
   218  	t.registerTests()
   219  	if t.listMode {
   220  		for _, tt := range t.tests {
   221  			fmt.Println(tt.name)
   222  		}
   223  		return
   224  	}
   225  
   226  	for _, name := range t.runNames {
   227  		if !t.testNames[name] {
   228  			fatalf("unknown test %q", name)
   229  		}
   230  	}
   231  
   232  	// On a few builders, make GOROOT unwritable to catch tests writing to it.
   233  	if strings.HasPrefix(os.Getenv("GO_BUILDER_NAME"), "linux-") {
   234  		if os.Getuid() == 0 {
   235  			// Don't bother making GOROOT unwritable:
   236  			// we're running as root, so permissions would have no effect.
   237  		} else {
   238  			xatexit(t.makeGOROOTUnwritable())
   239  		}
   240  	}
   241  
   242  	if !t.json {
   243  		if err := t.maybeLogMetadata(); err != nil {
   244  			t.failed = true
   245  			if t.keepGoing {
   246  				log.Printf("Failed logging metadata: %v", err)
   247  			} else {
   248  				fatalf("Failed logging metadata: %v", err)
   249  			}
   250  		}
   251  	}
   252  
   253  	var anyIncluded, someExcluded bool
   254  	for _, dt := range t.tests {
   255  		if !t.shouldRunTest(dt.name) {
   256  			someExcluded = true
   257  			continue
   258  		}
   259  		anyIncluded = true
   260  		dt := dt // dt used in background after this iteration
   261  		if err := dt.fn(&dt); err != nil {
   262  			t.runPending(&dt) // in case that hasn't been done yet
   263  			t.failed = true
   264  			if t.keepGoing {
   265  				log.Printf("Failed: %v", err)
   266  			} else {
   267  				fatalf("Failed: %v", err)
   268  			}
   269  		}
   270  	}
   271  	t.runPending(nil)
   272  	timelog("end", "dist test")
   273  	distSpan.done()
   274  	if debugTrace != "" {
   275  		writeTrace()
   276  	}
   277  
   278  	if !t.json {
   279  		if t.failed {
   280  			fmt.Println("\nFAILED")
   281  		} else if !anyIncluded {
   282  			fmt.Println()
   283  			errprintf("go tool dist: warning: %q matched no tests; use the -list flag to list available tests\n", t.runRxStr)
   284  			fmt.Println("NO TESTS TO RUN")
   285  		} else if someExcluded {
   286  			fmt.Println("\nALL TESTS PASSED (some were excluded)")
   287  		} else {
   288  			fmt.Println("\nALL TESTS PASSED")
   289  		}
   290  	}
   291  	if t.failed {
   292  		xexit(1)
   293  	}
   294  }
   295  
   296  func (t *tester) shouldRunTest(name string) bool {
   297  	if t.runRx != nil {
   298  		return t.runRx.MatchString(name) == t.runRxWant
   299  	}
   300  	if len(t.runNames) == 0 {
   301  		return true
   302  	}
   303  	return slices.Contains(t.runNames, name)
   304  }
   305  
   306  func (t *tester) maybeLogMetadata() error {
   307  	if t.compileOnly {
   308  		// We need to run a subprocess to log metadata. Don't do that
   309  		// on compile-only runs.
   310  		return nil
   311  	}
   312  	t.out("Test execution environment.")
   313  	// Helper binary to print system metadata (CPU model, etc). This is a
   314  	// separate binary from dist so it need not build with the bootstrap
   315  	// toolchain.
   316  	//
   317  	// TODO(prattmic): If we split dist bootstrap and dist test then this
   318  	// could be simplified to directly use internal/sysinfo here.
   319  	return t.dirCmd(filepath.Join(goroot, "src/cmd/internal/metadata"), gorootBinGo, []string{"run", "main.go"}).Run()
   320  }
   321  
   322  // testName returns the dist test name for a given package and variant.
   323  func testName(pkg, variant string) string {
   324  	name := pkg
   325  	if variant != "" {
   326  		name += ":" + variant
   327  	}
   328  	return name
   329  }
   330  
   331  // goTest represents all options to a "go test" command. The final command will
   332  // combine configuration from goTest and tester flags.
   333  type goTest struct {
   334  	short    bool     // If true, force -short
   335  	tags     []string // Build tags
   336  	race     bool     // Force -race
   337  	bench    bool     // Run benchmarks (briefly), not tests.
   338  	runTests string   // Regexp of tests to run
   339  	cpu      string   // If non-empty, -cpu flag
   340  	skip     string   // If non-empty, -skip flag
   341  
   342  	gcflags   string // If non-empty, build with -gcflags=all=X
   343  	ldflags   string // If non-empty, build with -ldflags=X
   344  	buildmode string // If non-empty, -buildmode flag
   345  
   346  	env []string // Environment variables to add, as KEY=VAL. KEY= unsets a variable
   347  
   348  	// timeout optionally raises the per-package test timeout to be at least this long.
   349  	// The zero value means to stay with the default test timeout.
   350  	// When adding new tests, this field generally doesn't need to be set, not unless
   351  	// the go commmand's default test timeout proves to be insufficient.
   352  	//
   353  	// In either case, the per-package test timeout get scaled by a multiplier,
   354  	// and applied only if the end result is longer than the go command's default
   355  	// test timeout.
   356  	timeout time.Duration
   357  
   358  	runOnHost bool // When cross-compiling, run this test on the host instead of guest
   359  
   360  	// variant, if non-empty, is a name used to distinguish different
   361  	// configurations of the same test package(s). If set, the Package field
   362  	// in test2json output is rewritten to pkg:variant.
   363  	variant string
   364  
   365  	// We have both pkg and pkgs as a convenience. Both may be set, in which
   366  	// case they will be combined. At least one must be set.
   367  	pkgs []string // Multiple packages to test
   368  	pkg  string   // A single package to test
   369  
   370  	testFlags []string // Additional flags accepted by this test
   371  	trace     string   // If non-empty, write go test -debug-trace output to <workdir>/<trace>.trace
   372  }
   373  
   374  // compileOnly reports whether this test is only for compiling,
   375  // indicated by runTests being set to '^$' and bench being false.
   376  func (opts *goTest) compileOnly() bool {
   377  	return opts.runTests == "^$" && !opts.bench
   378  }
   379  
   380  // scaledTimeout reports the per-package test timeout scaled by t.timeoutScale.
   381  func (opts *goTest) scaledTimeout(t *tester) time.Duration {
   382  	d := goTestDefaultTimeout
   383  	if opts.timeout != 0 {
   384  		d = opts.timeout
   385  	}
   386  	d *= time.Duration(t.timeoutScale)
   387  	return d
   388  }
   389  
   390  const goTestDefaultTimeout = 10 * time.Minute // Default value of go test -timeout flag.
   391  
   392  // bgCommand returns a go test Cmd and a post-Run flush function. The result
   393  // will write its output to stdout and stderr. If stdout==stderr, bgCommand
   394  // ensures Writes are serialized. The caller should call flush() after Cmd exits.
   395  func (opts *goTest) bgCommand(t *tester, stdout, stderr io.Writer) (cmd *exec.Cmd, flush func()) {
   396  	build, run, pkgs, testFlags, setupCmd := opts.buildArgs(t)
   397  
   398  	// Combine the flags.
   399  	args := append([]string{"test"}, build...)
   400  	if t.compileOnly || opts.compileOnly() {
   401  		args = append(args, "-c", "-o", os.DevNull)
   402  	} else {
   403  		args = append(args, run...)
   404  	}
   405  	args = append(args, pkgs...)
   406  	if !t.compileOnly && !opts.compileOnly() {
   407  		args = append(args, testFlags...)
   408  	}
   409  
   410  	cmd = exec.Command(gorootBinGo, args...)
   411  	setupCmd(cmd)
   412  	if t.json && opts.variant != "" {
   413  		// Rewrite Package in the JSON output to be pkg:variant.
   414  		//
   415  		// We only want to process JSON on the child's stdout. Ideally if
   416  		// stdout==stderr, we would also use the same testJSONFilter for
   417  		// cmd.Stdout and cmd.Stderr in order to keep the underlying
   418  		// interleaving of writes, but then it would see even partial writes
   419  		// interleaved, which would corrupt the JSON. So, we only process
   420  		// cmd.Stdout. This has another consequence though: if stdout==stderr,
   421  		// we have to serialize Writes in case the Writer is not concurrent
   422  		// safe. If we were just passing stdout/stderr through to exec, it would
   423  		// do this for us, but since we're wrapping stdout, we have to do it
   424  		// ourselves.
   425  		if stdout == stderr {
   426  			stdout = &lockedWriter{w: stdout}
   427  			stderr = stdout
   428  		}
   429  		f := &testJSONFilter{w: stdout, variant: opts.variant}
   430  		cmd.Stdout = f
   431  		flush = f.Flush
   432  	} else {
   433  		cmd.Stdout = stdout
   434  		flush = func() {}
   435  	}
   436  	cmd.Stderr = stderr
   437  
   438  	return cmd, flush
   439  }
   440  
   441  // run runs a go test and returns an error if it does not succeed.
   442  func (opts *goTest) run(t *tester) error {
   443  	cmd, flush := opts.bgCommand(t, os.Stdout, os.Stderr)
   444  	err := cmd.Run()
   445  	flush()
   446  	return err
   447  }
   448  
   449  // buildArgs is in internal helper for goTest that constructs the elements of
   450  // the "go test" command line. build is the flags for building the test. run is
   451  // the flags for running the test. pkgs is the list of packages to build and
   452  // run. testFlags is the list of flags to pass to the test package.
   453  //
   454  // The caller must call setupCmd on the resulting exec.Cmd to set its directory
   455  // and environment.
   456  func (opts *goTest) buildArgs(t *tester) (build, run, pkgs, testFlags []string, setupCmd func(*exec.Cmd)) {
   457  	run = append(run, "-count=1") // Disallow caching.
   458  	if d := opts.scaledTimeout(t); d > goTestDefaultTimeout {
   459  		run = append(run, "-timeout="+d.String())
   460  	}
   461  	if opts.short || t.short {
   462  		run = append(run, "-short")
   463  	}
   464  	var tags []string
   465  	if noOpt {
   466  		tags = append(tags, "noopt")
   467  	}
   468  	tags = append(tags, opts.tags...)
   469  	if len(tags) > 0 {
   470  		build = append(build, "-tags="+strings.Join(tags, ","))
   471  	}
   472  	if t.race || opts.race {
   473  		build = append(build, "-race")
   474  	}
   475  	if t.msan {
   476  		build = append(build, "-msan")
   477  	}
   478  	if t.asan {
   479  		build = append(build, "-asan")
   480  	}
   481  	if opts.bench {
   482  		// Run no tests.
   483  		run = append(run, "-run=^$")
   484  		// Run benchmarks briefly as a smoke test.
   485  		run = append(run, "-bench=.*", "-benchtime=.1s")
   486  	} else if opts.runTests != "" {
   487  		run = append(run, "-run="+opts.runTests)
   488  	}
   489  	if opts.cpu != "" {
   490  		run = append(run, "-cpu="+opts.cpu)
   491  	}
   492  	if opts.skip != "" {
   493  		run = append(run, "-skip="+opts.skip)
   494  	}
   495  	if t.json {
   496  		build = append(build, "-json")
   497  	}
   498  	if t.artifactsDir != "" {
   499  		run = append(run, "-artifacts", "-outputdir="+t.artifactsDir)
   500  	}
   501  
   502  	if opts.gcflags != "" {
   503  		build = append(build, "-gcflags=all="+opts.gcflags)
   504  	}
   505  	if opts.ldflags != "" {
   506  		build = append(build, "-ldflags="+opts.ldflags)
   507  	}
   508  	if t.asmflags != "" {
   509  		build = append(build, "-asmflags="+t.asmflags)
   510  	}
   511  	if opts.buildmode != "" {
   512  		build = append(build, "-buildmode="+opts.buildmode)
   513  	}
   514  	if opts.trace != "" {
   515  		build = append(build, maybeTraceFlag(opts.trace)...)
   516  	}
   517  
   518  	pkgs = opts.packages()
   519  
   520  	runOnHost := opts.runOnHost && (goarch != gohostarch || goos != gohostos)
   521  	needTestFlags := len(opts.testFlags) > 0 || runOnHost
   522  	if needTestFlags {
   523  		testFlags = append([]string{"-args"}, opts.testFlags...)
   524  	}
   525  	if runOnHost {
   526  		// -target is a special flag understood by tests that can run on the host
   527  		testFlags = append(testFlags, "-target="+goos+"/"+goarch)
   528  	}
   529  
   530  	setupCmd = func(cmd *exec.Cmd) {
   531  		setDir(cmd, filepath.Join(goroot, "src"))
   532  		if len(opts.env) != 0 {
   533  			for _, kv := range opts.env {
   534  				if i := strings.Index(kv, "="); i < 0 {
   535  					unsetEnv(cmd, kv[:len(kv)-1])
   536  				} else {
   537  					setEnv(cmd, kv[:i], kv[i+1:])
   538  				}
   539  			}
   540  		}
   541  		if runOnHost {
   542  			setEnv(cmd, "GOARCH", gohostarch)
   543  			setEnv(cmd, "GOOS", gohostos)
   544  		}
   545  	}
   546  
   547  	return
   548  }
   549  
   550  // packages returns the full list of packages to be run by this goTest. This
   551  // will always include at least one package.
   552  func (opts *goTest) packages() []string {
   553  	pkgs := opts.pkgs
   554  	if opts.pkg != "" {
   555  		pkgs = append(pkgs[:len(pkgs):len(pkgs)], opts.pkg)
   556  	}
   557  	if len(pkgs) == 0 {
   558  		panic("no packages")
   559  	}
   560  	return pkgs
   561  }
   562  
   563  // printSkip prints a skip message for all of goTest.
   564  func (opts *goTest) printSkip(t *tester, msg string) {
   565  	if t.json {
   566  		enc := json.NewEncoder(os.Stdout)
   567  		for _, pkg := range opts.packages() {
   568  			synthesizeSkipEvent(enc, pkg, msg)
   569  		}
   570  		return
   571  	}
   572  	fmt.Println(msg)
   573  }
   574  
   575  // ranGoTest and stdMatches are state closed over by the stdlib
   576  // testing func in registerStdTest below. The tests are run
   577  // sequentially, so there's no need for locks.
   578  //
   579  // ranGoBench and benchMatches are the same, but are only used
   580  // in -race mode.
   581  var (
   582  	ranGoTest  bool
   583  	stdMatches []string
   584  
   585  	ranGoBench   bool
   586  	benchMatches []string
   587  )
   588  
   589  func (t *tester) registerStdTest(pkg string) {
   590  	const stdTestHeading = "Testing packages." // known to addTest for a safety check
   591  	gcflags := gogcflags
   592  	name := testName(pkg, "")
   593  	if t.runRx == nil || t.runRx.MatchString(name) == t.runRxWant {
   594  		stdMatches = append(stdMatches, pkg)
   595  	}
   596  	t.addTest(name, stdTestHeading, func(dt *distTest) error {
   597  		if ranGoTest {
   598  			return nil
   599  		}
   600  		t.runPending(dt)
   601  		timelog("start", dt.name)
   602  		defer timelog("end", dt.name)
   603  		ranGoTest = true
   604  
   605  		stdSpan := startSpan("go test std cmd")
   606  		defer stdSpan.done()
   607  
   608  		return (&goTest{
   609  			gcflags: gcflags,
   610  			pkgs:    stdMatches,
   611  			trace:   "std",
   612  		}).run(t)
   613  	})
   614  }
   615  
   616  func (t *tester) registerRaceBenchTest(pkg string) {
   617  	const raceBenchHeading = "Running benchmarks briefly." // known to addTest for a safety check
   618  	name := testName(pkg, "racebench")
   619  	if t.runRx == nil || t.runRx.MatchString(name) == t.runRxWant {
   620  		benchMatches = append(benchMatches, pkg)
   621  	}
   622  	t.addTest(name, raceBenchHeading, func(dt *distTest) error {
   623  		if ranGoBench {
   624  			return nil
   625  		}
   626  		t.runPending(dt)
   627  		timelog("start", dt.name)
   628  		defer timelog("end", dt.name)
   629  		ranGoBench = true
   630  		return (&goTest{
   631  			// Include the variant even though there's no overlap in test names.
   632  			// This makes the test targets distinct, allowing our build system to record
   633  			// elapsed time for each one, which is useful for load-balancing test shards.
   634  			variant: "racebench",
   635  			timeout: 20 * time.Minute, // longer timeout for race with benchmarks
   636  			race:    true,
   637  			bench:   true,
   638  			cpu:     "4",
   639  			pkgs:    benchMatches,
   640  		}).run(t)
   641  	})
   642  }
   643  
   644  func (t *tester) registerTests() {
   645  	// Fast path to avoid the ~1 second of `go list std cmd` when
   646  	// the caller lists specific tests to run. (as the continuous
   647  	// build coordinator does).
   648  	if len(t.runNames) > 0 {
   649  		for _, name := range t.runNames {
   650  			if !strings.Contains(name, ":") {
   651  				t.registerStdTest(name)
   652  			} else if strings.HasSuffix(name, ":racebench") {
   653  				t.registerRaceBenchTest(strings.TrimSuffix(name, ":racebench"))
   654  			}
   655  		}
   656  	} else {
   657  		// Use 'go list std cmd' to get a list of all Go packages
   658  		// that running 'go test std cmd' could find problems in.
   659  		// (In race test mode, also set -tags=race.)
   660  		// This includes vendored packages and other
   661  		// packages without tests so that 'dist test' finds if any of
   662  		// them don't build, have a problem reported by high-confidence
   663  		// vet checks that come with 'go test', and anything else it
   664  		// may check in the future. See go.dev/issue/60463.
   665  		// Most packages have tests, so there is not much saved
   666  		// by skipping non-test packages.
   667  		// For the packages without any test files,
   668  		// 'go test' knows not to actually build a test binary,
   669  		// so the only cost is the vet, and we still want to run vet.
   670  		cmd := exec.Command(gorootBinGo, "list")
   671  		if t.race {
   672  			cmd.Args = append(cmd.Args, "-tags=race")
   673  		}
   674  		cmd.Args = append(cmd.Args, "std", "cmd")
   675  		cmd.Stderr = new(bytes.Buffer)
   676  		all, err := cmd.Output()
   677  		if err != nil {
   678  			fatalf("Error running go list std cmd: %v:\n%s", err, cmd.Stderr)
   679  		}
   680  		pkgs := strings.Fields(string(all))
   681  		for _, pkg := range pkgs {
   682  			if t.short && (strings.HasPrefix(pkg, "vendor/") || strings.HasPrefix(pkg, "cmd/vendor/")) {
   683  				// Vendored code has no tests, and we don't care too much about vet errors
   684  				// since we can't modify the code, so skip the tests in short mode.
   685  				// We still let the longtest builders vet them.
   686  				continue
   687  			}
   688  			t.registerStdTest(pkg)
   689  		}
   690  		if t.race && !t.short {
   691  			for _, pkg := range pkgs {
   692  				if t.packageHasBenchmarks(pkg) {
   693  					t.registerRaceBenchTest(pkg)
   694  				}
   695  			}
   696  		}
   697  	}
   698  
   699  	if t.race {
   700  		return
   701  	}
   702  
   703  	// Test the os/user package in the pure-Go mode too.
   704  	if !t.compileOnly {
   705  		t.registerTest("os/user with tag osusergo",
   706  			&goTest{
   707  				variant: "osusergo",
   708  				tags:    []string{"osusergo"},
   709  				pkg:     "os/user",
   710  			})
   711  	}
   712  
   713  	// Tests that the nethttpomithttp2* build tags don't rot too much,
   714  	// even if there's not a regular builder on them.
   715  	for _, tag := range []string{"nethttpomithttp2", "nethttpomithttp2server", "nethttpomithttp2client"} {
   716  		t.registerTest("net/http with tag "+tag, &goTest{
   717  			variant: tag,
   718  			tags:    []string{tag},
   719  			pkg:     "net/http",
   720  		})
   721  	}
   722  
   723  	// Check that all crypto packages compile with the purego build tag.
   724  	t.registerTest("crypto with tag purego (build and vet only)", &goTest{
   725  		variant:  "purego",
   726  		tags:     []string{"purego"},
   727  		pkg:      "crypto/...",
   728  		runTests: "^$", // only ensure they compile
   729  	})
   730  
   731  	// Check that all crypto packages compile (and test correctly, in longmode) with fips.
   732  	if t.fips140Supported() {
   733  		// Test standard crypto packages with fips140=on.
   734  		t.registerTest("GOFIPS140=latest go test crypto/...", &goTest{
   735  			variant: "gofips140",
   736  			env:     []string{"GOFIPS140=latest"},
   737  			pkg:     "crypto/...",
   738  		})
   739  
   740  		// Test that earlier FIPS snapshots build.
   741  		// In long mode, test that they work too.
   742  		for _, version := range fips140Versions() {
   743  			suffix := " # (build and vet only)"
   744  			run := "^$" // only ensure they compile
   745  			if !t.short {
   746  				suffix = ""
   747  				run = ""
   748  			}
   749  			t.registerTest("GOFIPS140="+version+" go test crypto/..."+suffix, &goTest{
   750  				variant:  "gofips140-" + version,
   751  				pkg:      "crypto/...",
   752  				runTests: run,
   753  				env:      []string{"GOFIPS140=" + version, "GOMODCACHE=" + filepath.Join(workdir, "fips-"+version)},
   754  			})
   755  		}
   756  	}
   757  
   758  	// Test GOEXPERIMENT=nojsonv2.
   759  	if !strings.Contains(goexperiment, "nojsonv2") {
   760  		t.registerTest("GOEXPERIMENT=nojsonv2 go test encoding/json/...", &goTest{
   761  			variant: "nojsonv2",
   762  			env:     []string{"GOEXPERIMENT=" + goexperiments("nojsonv2")},
   763  			pkg:     "encoding/json/...",
   764  		})
   765  	}
   766  
   767  	// Test GOEXPERIMENT=runtimesecret.
   768  	if !strings.Contains(goexperiment, "runtimesecret") {
   769  		t.registerTest("GOEXPERIMENT=runtimesecret go test runtime/secret/...", &goTest{
   770  			variant: "runtimesecret",
   771  			env:     []string{"GOEXPERIMENT=" + goexperiments("runtimesecret")},
   772  			pkg:     "runtime/secret/...",
   773  		})
   774  	}
   775  
   776  	// Test GOEXPERIMENT=simd.
   777  	if !strings.Contains(goexperiment, "simd") {
   778  		// simd package is portable.
   779  		t.registerTest("GOEXPERIMENT=simd go test simd", &goTest{
   780  			variant: "simd",
   781  			env:     []string{"GOEXPERIMENT=" + goexperiments("simd")},
   782  			pkg:     "simd",
   783  		})
   784  		// simd/archsimd supports amd64, arm64, and wasm.
   785  		archsimdSupported := goarch == "amd64" || goarch == "arm64" || goarch == "wasm"
   786  		if archsimdSupported {
   787  			t.registerTest("GOEXPERIMENT=simd go test simd/archsimd/...", &goTest{
   788  				variant: "simd",
   789  				env:     []string{"GOEXPERIMENT=" + goexperiments("simd")},
   790  				pkg:     "simd/archsimd/...",
   791  			})
   792  		}
   793  	}
   794  
   795  	// Test ios/amd64 for the iOS simulator.
   796  	if goos == "darwin" && goarch == "amd64" && t.cgoEnabled {
   797  		t.registerTest("GOOS=ios on darwin/amd64",
   798  			&goTest{
   799  				variant:  "amd64ios",
   800  				runTests: "SystemRoots",
   801  				env:      []string{"GOOS=ios", "CGO_ENABLED=1"},
   802  				pkg:      "crypto/x509",
   803  			})
   804  	}
   805  
   806  	// GC debug mode tests. We only run these in long-test mode
   807  	// (with GO_TEST_SHORT=0) because this is just testing a
   808  	// non-critical debug setting.
   809  	if !t.compileOnly && !t.short {
   810  		t.registerTest("GODEBUG=gcstoptheworld=2 archive/zip",
   811  			&goTest{
   812  				variant: "gcstoptheworld2",
   813  				short:   true,
   814  				env:     []string{"GODEBUG=gcstoptheworld=2"},
   815  				pkg:     "archive/zip",
   816  			})
   817  		t.registerTest("GODEBUG=gccheckmark=1 runtime",
   818  			&goTest{
   819  				variant: "gccheckmark",
   820  				short:   true,
   821  				env:     []string{"GODEBUG=gccheckmark=1"},
   822  				pkg:     "runtime",
   823  			})
   824  	}
   825  
   826  	// Spectre mitigation smoke test.
   827  	if goos == "linux" && goarch == "amd64" && !(gogcflags == "-spectre=all" && t.asmflags == "all=-spectre=all") {
   828  		// Pick a bunch of packages known to have some assembly.
   829  		pkgs := []string{"internal/runtime/...", "reflect", "crypto/..."}
   830  		if !t.short {
   831  			pkgs = append(pkgs, "runtime")
   832  		}
   833  		t.registerTest("spectre",
   834  			&goTest{
   835  				variant: "spectre",
   836  				short:   true,
   837  				env:     []string{"GOFLAGS=-gcflags=all=-spectre=all -asmflags=all=-spectre=all"},
   838  				pkgs:    pkgs,
   839  			})
   840  	}
   841  
   842  	// morestack tests. We only run these in long-test mode
   843  	// (with GO_TEST_SHORT=0) because the runtime test is
   844  	// already quite long and mayMoreStackMove makes it about
   845  	// twice as slow.
   846  	if !t.compileOnly && !t.short {
   847  		// hooks is the set of maymorestack hooks to test with.
   848  		hooks := []string{"mayMoreStackPreempt", "mayMoreStackMove"}
   849  		// hookPkgs is the set of package patterns to apply
   850  		// the maymorestack hook to.
   851  		hookPkgs := []string{"runtime/...", "reflect", "sync"}
   852  		// unhookPkgs is the set of package patterns to
   853  		// exclude from hookPkgs.
   854  		unhookPkgs := []string{"runtime/testdata/..."}
   855  		for _, hook := range hooks {
   856  			// Construct the build flags to use the
   857  			// maymorestack hook in the compiler and
   858  			// assembler. We pass this via the GOFLAGS
   859  			// environment variable so that it applies to
   860  			// both the test itself and to binaries built
   861  			// by the test.
   862  			goFlagsList := []string{}
   863  			for _, flag := range []string{"-gcflags", "-asmflags"} {
   864  				for _, hookPkg := range hookPkgs {
   865  					goFlagsList = append(goFlagsList, flag+"="+hookPkg+"=-d=maymorestack=runtime."+hook)
   866  				}
   867  				for _, unhookPkg := range unhookPkgs {
   868  					goFlagsList = append(goFlagsList, flag+"="+unhookPkg+"=")
   869  				}
   870  			}
   871  			goFlags := strings.Join(goFlagsList, " ")
   872  
   873  			t.registerTest("maymorestack="+hook,
   874  				&goTest{
   875  					variant: hook,
   876  					short:   true,
   877  					env:     []string{"GOFLAGS=" + goFlags},
   878  					pkgs:    []string{"runtime", "reflect", "sync"},
   879  				})
   880  		}
   881  	}
   882  
   883  	// Test that internal linking of standard packages does not
   884  	// require libgcc. This ensures that we can install a Go
   885  	// release on a system that does not have a C compiler
   886  	// installed and still build Go programs (that don't use cgo).
   887  	for _, pkg := range cgoPackages {
   888  		if !t.internalLink() {
   889  			break
   890  		}
   891  
   892  		// ARM libgcc may be Thumb, which internal linking does not support.
   893  		if goarch == "arm" {
   894  			break
   895  		}
   896  
   897  		// What matters is that the tests build and start up.
   898  		// Skip expensive tests, especially x509 TestSystemRoots.
   899  		run := "^Test[^CS]"
   900  		if pkg == "net" {
   901  			run = "TestTCPStress"
   902  		}
   903  		t.registerTest("Testing without libgcc.",
   904  			&goTest{
   905  				variant:  "nolibgcc",
   906  				ldflags:  "-linkmode=internal -libgcc=none",
   907  				runTests: run,
   908  				pkg:      pkg,
   909  			})
   910  	}
   911  
   912  	// Stub out following test on alpine until 54354 resolved.
   913  	builderName := os.Getenv("GO_BUILDER_NAME")
   914  	disablePIE := strings.HasSuffix(builderName, "-alpine")
   915  
   916  	// Test internal linking of PIE binaries where it is supported.
   917  	if t.internalLinkPIE() && !disablePIE {
   918  		t.registerTest("internal linking, -buildmode=pie",
   919  			&goTest{
   920  				variant:   "pie_internal",
   921  				buildmode: "pie",
   922  				ldflags:   "-linkmode=internal",
   923  				env:       []string{"CGO_ENABLED=0"},
   924  				pkg:       "reflect",
   925  			})
   926  		t.registerTest("internal linking, -buildmode=pie",
   927  			&goTest{
   928  				variant:   "pie_internal",
   929  				buildmode: "pie",
   930  				ldflags:   "-linkmode=internal",
   931  				env:       []string{"CGO_ENABLED=0"},
   932  				pkg:       "crypto/internal/fips140test",
   933  				runTests:  "TestFIPSCheck",
   934  			})
   935  		// Also test a cgo package.
   936  		if t.cgoEnabled && t.internalLink() && !disablePIE {
   937  			t.registerTest("internal linking, -buildmode=pie",
   938  				&goTest{
   939  					variant:   "pie_internal",
   940  					buildmode: "pie",
   941  					ldflags:   "-linkmode=internal",
   942  					pkg:       "os/user",
   943  				})
   944  		}
   945  	}
   946  
   947  	if t.extLink() && !t.compileOnly {
   948  		if goos != "android" { // Android does not support non-PIE linking
   949  			t.registerTest("external linking, -buildmode=exe",
   950  				&goTest{
   951  					variant:   "exe_external",
   952  					buildmode: "exe",
   953  					ldflags:   "-linkmode=external",
   954  					env:       []string{"CGO_ENABLED=1"},
   955  					pkg:       "crypto/internal/fips140test",
   956  					runTests:  "TestFIPSCheck",
   957  				})
   958  		}
   959  		if t.externalLinkPIE() && !disablePIE {
   960  			t.registerTest("external linking, -buildmode=pie",
   961  				&goTest{
   962  					variant:   "pie_external",
   963  					buildmode: "pie",
   964  					ldflags:   "-linkmode=external",
   965  					env:       []string{"CGO_ENABLED=1"},
   966  					pkg:       "crypto/internal/fips140test",
   967  					runTests:  "TestFIPSCheck",
   968  				})
   969  		}
   970  	}
   971  
   972  	// sync tests
   973  	if !t.compileOnly && t.hasParallelism() {
   974  		t.registerTest("sync -cpu=10",
   975  			&goTest{
   976  				variant: "cpu10",
   977  				cpu:     "10",
   978  				pkg:     "sync",
   979  			})
   980  	}
   981  
   982  	const cgoHeading = "Testing cgo"
   983  	if t.cgoEnabled {
   984  		t.registerCgoTests(cgoHeading)
   985  	}
   986  
   987  	if goos == "wasip1" {
   988  		t.registerTest("wasip1 host tests",
   989  			&goTest{
   990  				variant:   "host",
   991  				pkg:       "internal/runtime/wasitest",
   992  				runOnHost: true,
   993  			})
   994  	}
   995  
   996  	// Runtime CPU tests.
   997  	if !t.compileOnly && t.hasParallelism() {
   998  		for i := 1; i <= 4; i *= 2 {
   999  			t.registerTest(fmt.Sprintf("GOMAXPROCS=2 runtime -cpu=%d -quick", i),
  1000  				&goTest{
  1001  					variant:   "cpu" + strconv.Itoa(i),
  1002  					cpu:       strconv.Itoa(i),
  1003  					gcflags:   gogcflags,
  1004  					short:     true,
  1005  					testFlags: []string{"-quick"},
  1006  					// We set GOMAXPROCS=2 in addition to -cpu=1,2,4 in order to test runtime bootstrap code,
  1007  					// creation of first goroutines and first garbage collections in the parallel setting.
  1008  					env: []string{"GOMAXPROCS=2"},
  1009  					pkg: "runtime",
  1010  				})
  1011  		}
  1012  	}
  1013  
  1014  	if t.raceDetectorSupported() && !t.msan && !t.asan {
  1015  		// N.B. -race is incompatible with -msan and -asan.
  1016  		t.registerRaceTests()
  1017  	}
  1018  
  1019  	// These tests will be skipped as part of the initial go test std cmd invocation for
  1020  	// js and wasip1 and need to be run on the host. Register them specially here.
  1021  	if goos == "js" || goos == "wasip1" {
  1022  		t.registerTest("../test",
  1023  			&goTest{
  1024  				variant:   "host",
  1025  				pkg:       "cmd/internal/testdir",
  1026  				runOnHost: true,
  1027  			},
  1028  		)
  1029  	}
  1030  }
  1031  
  1032  // addTest adds an arbitrary test callback to the test list.
  1033  //
  1034  // name must uniquely identify the test and heading must be non-empty.
  1035  func (t *tester) addTest(name, heading string, fn func(*distTest) error) {
  1036  	if t.testNames[name] {
  1037  		panic("duplicate registered test name " + name)
  1038  	}
  1039  	if heading == "" {
  1040  		panic("empty heading")
  1041  	}
  1042  	// Two simple checks for cases that would conflict with the fast path in registerTests.
  1043  	if !strings.Contains(name, ":") && heading != "Testing packages." {
  1044  		panic("empty variant is reserved exclusively for registerStdTest")
  1045  	} else if strings.HasSuffix(name, ":racebench") && heading != "Running benchmarks briefly." {
  1046  		panic("racebench variant is reserved exclusively for registerRaceBenchTest")
  1047  	}
  1048  	if t.testNames == nil {
  1049  		t.testNames = make(map[string]bool)
  1050  	}
  1051  	t.testNames[name] = true
  1052  	t.tests = append(t.tests, distTest{
  1053  		name:    name,
  1054  		heading: heading,
  1055  		fn:      fn,
  1056  	})
  1057  }
  1058  
  1059  type registerTestOpt interface {
  1060  	isRegisterTestOpt()
  1061  }
  1062  
  1063  // rtSkipFunc is a registerTest option that runs a skip check function before
  1064  // running the test.
  1065  type rtSkipFunc struct {
  1066  	skip func(*distTest) (string, bool) // Return message, true to skip the test
  1067  }
  1068  
  1069  func (rtSkipFunc) isRegisterTestOpt() {}
  1070  
  1071  // registerTest registers a test that runs the given goTest.
  1072  //
  1073  // Each Go package in goTest will have a corresponding test
  1074  // "<pkg>:<variant>", which must uniquely identify the test.
  1075  //
  1076  // heading and test.variant must be non-empty.
  1077  func (t *tester) registerTest(heading string, test *goTest, opts ...registerTestOpt) {
  1078  	var skipFunc func(*distTest) (string, bool)
  1079  	for _, opt := range opts {
  1080  		switch opt := opt.(type) {
  1081  		case rtSkipFunc:
  1082  			skipFunc = opt.skip
  1083  		}
  1084  	}
  1085  	// Register each test package as a separate test.
  1086  	register1 := func(test *goTest) {
  1087  		if test.variant == "" {
  1088  			panic("empty variant")
  1089  		}
  1090  		name := testName(test.pkg, test.variant)
  1091  		t.addTest(name, heading, func(dt *distTest) error {
  1092  			if skipFunc != nil {
  1093  				msg, skip := skipFunc(dt)
  1094  				if skip {
  1095  					test.printSkip(t, msg)
  1096  					return nil
  1097  				}
  1098  			}
  1099  			w := &work{dt: dt}
  1100  			w.cmd, w.flush = test.bgCommand(t, &w.out, &w.out)
  1101  			t.worklist = append(t.worklist, w)
  1102  			return nil
  1103  		})
  1104  	}
  1105  	if test.pkg != "" && len(test.pkgs) == 0 {
  1106  		// Common case. Avoid copying.
  1107  		register1(test)
  1108  		return
  1109  	}
  1110  	// TODO(dmitshur,austin): It might be better to unify the execution of 'go test pkg'
  1111  	// invocations for the same variant to be done with a single 'go test pkg1 pkg2 pkg3'
  1112  	// command, just like it's already done in registerStdTest and registerRaceBenchTest.
  1113  	// Those methods accumulate matched packages in stdMatches and benchMatches slices,
  1114  	// and we can extend that mechanism to work for all other equal variant registrations.
  1115  	// Do the simple thing to start with.
  1116  	for _, pkg := range test.packages() {
  1117  		test1 := *test
  1118  		test1.pkg, test1.pkgs = pkg, nil
  1119  		register1(&test1)
  1120  	}
  1121  }
  1122  
  1123  // dirCmd constructs a Cmd intended to be run in the foreground.
  1124  // The command will be run in dir, and Stdout and Stderr will go to os.Stdout
  1125  // and os.Stderr.
  1126  func (t *tester) dirCmd(dir string, cmdline ...any) *exec.Cmd {
  1127  	bin, args := flattenCmdline(cmdline)
  1128  	cmd := exec.Command(bin, args...)
  1129  	if filepath.IsAbs(dir) {
  1130  		setDir(cmd, dir)
  1131  	} else {
  1132  		setDir(cmd, filepath.Join(goroot, dir))
  1133  	}
  1134  	cmd.Stdout = os.Stdout
  1135  	cmd.Stderr = os.Stderr
  1136  	if vflag > 1 {
  1137  		errprintf("%#q\n", cmd)
  1138  	}
  1139  	return cmd
  1140  }
  1141  
  1142  // flattenCmdline flattens a mixture of string and []string as single list
  1143  // and then interprets it as a command line: first element is binary, then args.
  1144  func flattenCmdline(cmdline []any) (bin string, args []string) {
  1145  	var list []string
  1146  	for _, x := range cmdline {
  1147  		switch x := x.(type) {
  1148  		case string:
  1149  			list = append(list, x)
  1150  		case []string:
  1151  			list = append(list, x...)
  1152  		default:
  1153  			panic("invalid dirCmd argument type: " + reflect.TypeOf(x).String())
  1154  		}
  1155  	}
  1156  
  1157  	bin = list[0]
  1158  	if !filepath.IsAbs(bin) {
  1159  		panic("command is not absolute: " + bin)
  1160  	}
  1161  	return bin, list[1:]
  1162  }
  1163  
  1164  func (t *tester) iOS() bool {
  1165  	return goos == "ios"
  1166  }
  1167  
  1168  func (t *tester) out(v string) {
  1169  	if t.json {
  1170  		return
  1171  	}
  1172  	if t.banner == "" {
  1173  		return
  1174  	}
  1175  	fmt.Println("\n" + t.banner + v)
  1176  }
  1177  
  1178  // extLink reports whether the current goos/goarch supports
  1179  // external linking.
  1180  func (t *tester) extLink() bool {
  1181  	if !cgoEnabled[goos+"/"+goarch] {
  1182  		return false
  1183  	}
  1184  	if goarch == "ppc64" && goos != "aix" && goos != "linux" {
  1185  		return false
  1186  	}
  1187  	return true
  1188  }
  1189  
  1190  func (t *tester) internalLink() bool {
  1191  	if gohostos == "dragonfly" {
  1192  		// linkmode=internal fails on dragonfly since errno is a TLS relocation.
  1193  		return false
  1194  	}
  1195  	if goos == "android" {
  1196  		return false
  1197  	}
  1198  	if goos == "ios" {
  1199  		return false
  1200  	}
  1201  	// Internally linking cgo is incomplete on some architectures.
  1202  	// https://golang.org/issue/10373
  1203  	// https://golang.org/issue/14449
  1204  	if goarch == "mips64" || goarch == "mips64le" || goarch == "mips" || goarch == "mipsle" || goarch == "riscv64" {
  1205  		return false
  1206  	}
  1207  	if goos == "aix" {
  1208  		// linkmode=internal isn't supported.
  1209  		return false
  1210  	}
  1211  	if t.msan || t.asan {
  1212  		// linkmode=internal isn't supported by msan or asan.
  1213  		return false
  1214  	}
  1215  	return true
  1216  }
  1217  
  1218  func (t *tester) internalLinkPIE() bool {
  1219  	if t.msan || t.asan {
  1220  		// linkmode=internal isn't supported by msan or asan.
  1221  		return false
  1222  	}
  1223  	switch goos + "-" + goarch {
  1224  	case "darwin-amd64", "darwin-arm64",
  1225  		"linux-amd64", "linux-arm64", "linux-loong64", "linux-ppc64", "linux-ppc64le", "linux-s390x",
  1226  		"android-arm64",
  1227  		"windows-amd64", "windows-386", "windows-arm64":
  1228  		return true
  1229  	}
  1230  	return false
  1231  }
  1232  
  1233  func (t *tester) externalLinkPIE() bool {
  1234  	// General rule is if -buildmode=pie and -linkmode=external both work, then they work together.
  1235  	return t.internalLinkPIE() && t.extLink()
  1236  }
  1237  
  1238  // supportedBuildmode reports whether the given build mode is supported.
  1239  func (t *tester) supportedBuildmode(mode string) bool {
  1240  	switch mode {
  1241  	case "c-archive", "c-shared", "shared", "plugin", "pie":
  1242  	default:
  1243  		fatalf("internal error: unknown buildmode %s", mode)
  1244  		return false
  1245  	}
  1246  
  1247  	return buildModeSupported("gc", mode, goos, goarch)
  1248  }
  1249  
  1250  func (t *tester) registerCgoTests(heading string) {
  1251  	cgoTest := func(variant string, subdir, linkmode, buildmode string, opts ...registerTestOpt) *goTest {
  1252  		gt := &goTest{
  1253  			variant:   variant,
  1254  			pkg:       "cmd/cgo/internal/" + subdir,
  1255  			buildmode: buildmode,
  1256  		}
  1257  		var ldflags []string
  1258  		if linkmode != "auto" {
  1259  			// "auto" is the default, so avoid cluttering the command line for "auto"
  1260  			ldflags = append(ldflags, "-linkmode="+linkmode)
  1261  		}
  1262  
  1263  		if linkmode == "internal" {
  1264  			gt.tags = append(gt.tags, "internal")
  1265  			if buildmode == "pie" {
  1266  				gt.tags = append(gt.tags, "internal_pie")
  1267  			}
  1268  		}
  1269  		if buildmode == "static" {
  1270  			// This isn't actually a Go buildmode, just a convenient way to tell
  1271  			// cgoTest we want static linking.
  1272  			gt.buildmode = ""
  1273  			switch linkmode {
  1274  			case "external":
  1275  				ldflags = append(ldflags, `-extldflags "-static -pthread"`)
  1276  			case "auto":
  1277  				gt.env = append(gt.env, "CGO_LDFLAGS=-static -pthread")
  1278  			default:
  1279  				panic("unknown linkmode with static build: " + linkmode)
  1280  			}
  1281  			gt.tags = append(gt.tags, "static")
  1282  		}
  1283  		gt.ldflags = strings.Join(ldflags, " ")
  1284  
  1285  		t.registerTest(heading, gt, opts...)
  1286  		return gt
  1287  	}
  1288  
  1289  	// test, testtls, and testnocgo are run with linkmode="auto", buildmode=""
  1290  	// as part of go test cmd. Here we only have to register the non-default
  1291  	// build modes of these tests.
  1292  
  1293  	// Stub out various buildmode=pie tests  on alpine until 54354 resolved.
  1294  	builderName := os.Getenv("GO_BUILDER_NAME")
  1295  	disablePIE := strings.HasSuffix(builderName, "-alpine")
  1296  
  1297  	if t.internalLink() {
  1298  		cgoTest("internal", "test", "internal", "")
  1299  	}
  1300  
  1301  	os := gohostos
  1302  	p := gohostos + "/" + goarch
  1303  	switch os {
  1304  	case "darwin", "windows":
  1305  		if !t.extLink() {
  1306  			break
  1307  		}
  1308  		// test linkmode=external, but __thread not supported, so skip testtls.
  1309  		cgoTest("external", "test", "external", "")
  1310  
  1311  		gt := cgoTest("external-s", "test", "external", "")
  1312  		gt.ldflags += " -s"
  1313  
  1314  		if t.supportedBuildmode("pie") && !disablePIE {
  1315  			cgoTest("auto-pie", "test", "auto", "pie")
  1316  			if t.internalLink() && t.internalLinkPIE() {
  1317  				cgoTest("internal-pie", "test", "internal", "pie")
  1318  			}
  1319  		}
  1320  
  1321  	case "aix", "android", "dragonfly", "freebsd", "linux", "netbsd", "openbsd":
  1322  		gt := cgoTest("external-g0", "test", "external", "")
  1323  		gt.env = append(gt.env, "CGO_CFLAGS=-g0 -fdiagnostics-color")
  1324  
  1325  		cgoTest("external", "testtls", "external", "")
  1326  		switch {
  1327  		case os == "aix":
  1328  			// no static linking
  1329  		case p == "freebsd/arm":
  1330  			// -fPIC compiled tls code will use __tls_get_addr instead
  1331  			// of __aeabi_read_tp, however, on FreeBSD/ARM, __tls_get_addr
  1332  			// is implemented in rtld-elf, so -fPIC isn't compatible with
  1333  			// static linking on FreeBSD/ARM with clang. (cgo depends on
  1334  			// -fPIC fundamentally.)
  1335  		default:
  1336  			// Check for static linking support
  1337  			var staticCheck rtSkipFunc
  1338  			ccName := compilerEnvLookup("CC", defaultcc, goos, goarch)
  1339  			cc, err := exec.LookPath(ccName)
  1340  			if err != nil {
  1341  				staticCheck.skip = func(*distTest) (string, bool) {
  1342  					return fmt.Sprintf("$CC (%q) not found, skip cgo static linking test.", ccName), true
  1343  				}
  1344  			} else {
  1345  				cmd := t.dirCmd("src/cmd/cgo/internal/test", cc, "-xc", "-o", "/dev/null", "-static", "-")
  1346  				cmd.Stdin = strings.NewReader("int main() {}")
  1347  				cmd.Stdout, cmd.Stderr = nil, nil // Discard output
  1348  				if err := cmd.Run(); err != nil {
  1349  					// Skip these tests
  1350  					staticCheck.skip = func(*distTest) (string, bool) {
  1351  						return "No support for static linking found (lacks libc.a?), skip cgo static linking test.", true
  1352  					}
  1353  				}
  1354  			}
  1355  
  1356  			// Doing a static link with boringcrypto gets
  1357  			// a C linker warning on Linux.
  1358  			// in function `bio_ip_and_port_to_socket_and_addr':
  1359  			// warning: Using 'getaddrinfo' in statically linked applications requires at runtime the shared libraries from the glibc version used for linking
  1360  			if staticCheck.skip == nil && goos == "linux" && strings.Contains(goexperiment, "boringcrypto") {
  1361  				staticCheck.skip = func(*distTest) (string, bool) {
  1362  					return "skipping static linking check on Linux when using boringcrypto to avoid C linker warning about getaddrinfo", true
  1363  				}
  1364  			}
  1365  
  1366  			// Static linking tests
  1367  			if goos != "android" && p != "netbsd/arm" && !t.msan && !t.asan {
  1368  				// TODO(#56629): Why does this fail on netbsd-arm?
  1369  				// TODO(#70080): Why does this fail with msan?
  1370  				// asan doesn't support static linking (this is an explicit build error on the C side).
  1371  				cgoTest("static", "testtls", "external", "static", staticCheck)
  1372  			}
  1373  			cgoTest("external", "testnocgo", "external", "", staticCheck)
  1374  			if goos != "android" && !t.msan && !t.asan {
  1375  				// TODO(#70080): Why does this fail with msan?
  1376  				// asan doesn't support static linking (this is an explicit build error on the C side).
  1377  				cgoTest("static", "testnocgo", "external", "static", staticCheck)
  1378  				cgoTest("static", "test", "external", "static", staticCheck)
  1379  				// -static in CGO_LDFLAGS triggers a different code path
  1380  				// than -static in -extldflags, so test both.
  1381  				// See issue #16651.
  1382  				if goarch != "loong64" && !t.msan && !t.asan {
  1383  					// TODO(#56623): Why does this fail on loong64?
  1384  					cgoTest("auto-static", "test", "auto", "static", staticCheck)
  1385  				}
  1386  			}
  1387  
  1388  			// PIE linking tests
  1389  			if t.supportedBuildmode("pie") && !disablePIE {
  1390  				cgoTest("auto-pie", "test", "auto", "pie")
  1391  				if t.internalLink() && t.internalLinkPIE() {
  1392  					cgoTest("internal-pie", "test", "internal", "pie")
  1393  				}
  1394  				cgoTest("auto-pie", "testtls", "auto", "pie")
  1395  				cgoTest("auto-pie", "testnocgo", "auto", "pie")
  1396  			}
  1397  		}
  1398  	}
  1399  }
  1400  
  1401  // runPending runs pending test commands, in parallel, emitting headers as appropriate.
  1402  // When finished, it emits header for nextTest, which is going to run after the
  1403  // pending commands are done (and runPending returns).
  1404  // A test should call runPending if it wants to make sure that it is not
  1405  // running in parallel with earlier tests, or if it has some other reason
  1406  // for needing the earlier tests to be done.
  1407  func (t *tester) runPending(nextTest *distTest) {
  1408  	worklist := t.worklist
  1409  	t.worklist = nil
  1410  	var pendingSpan span
  1411  	if len(worklist) > 0 {
  1412  		pendingSpan = startSpan("runPending")
  1413  	}
  1414  	maxbg := runtime.GOMAXPROCS(0)
  1415  	for i, w := range worklist {
  1416  		w.start = make(chan bool)
  1417  		w.end = make(chan struct{})
  1418  		// w.cmd must be set up to write to w.out. We can't check that, but we
  1419  		// can check for easy mistakes.
  1420  		if w.cmd.Stdout == nil || w.cmd.Stdout == os.Stdout || w.cmd.Stderr == nil || w.cmd.Stderr == os.Stderr {
  1421  			panic("work.cmd.Stdout/Stderr must be redirected")
  1422  		}
  1423  		go func(w *work) {
  1424  			if !<-w.start {
  1425  				timelog("skip", w.dt.name)
  1426  				w.printSkip(t, "skipped due to earlier error")
  1427  			} else {
  1428  				timelog("start", w.dt.name)
  1429  				s := startSpanTID(w.dt.name, uint64(i%maxbg+1))
  1430  				w.err = w.cmd.Run()
  1431  				if w.flush != nil {
  1432  					w.flush()
  1433  				}
  1434  				s.done()
  1435  				if w.err != nil {
  1436  					if isUnsupportedVMASize(w) {
  1437  						timelog("skip", w.dt.name)
  1438  						w.out.Reset()
  1439  						w.printSkip(t, "skipped due to unsupported VMA")
  1440  						w.err = nil
  1441  					}
  1442  				}
  1443  			}
  1444  			timelog("end", w.dt.name)
  1445  			w.end <- struct{}{}
  1446  		}(w)
  1447  	}
  1448  
  1449  	started := 0
  1450  	ended := 0
  1451  	var last *distTest
  1452  	for ended < len(worklist) {
  1453  		for started < len(worklist) && started-ended < maxbg {
  1454  			w := worklist[started]
  1455  			started++
  1456  			w.start <- !t.failed || t.keepGoing
  1457  		}
  1458  		w := worklist[ended]
  1459  		dt := w.dt
  1460  		if t.lastHeading != dt.heading {
  1461  			t.lastHeading = dt.heading
  1462  			t.out(dt.heading)
  1463  		}
  1464  		if dt != last {
  1465  			// Assumes all the entries for a single dt are in one worklist.
  1466  			last = w.dt
  1467  			if vflag > 0 {
  1468  				fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1469  			}
  1470  		}
  1471  		if vflag > 1 {
  1472  			errprintf("%#q\n", w.cmd)
  1473  		}
  1474  		ended++
  1475  		<-w.end
  1476  		os.Stdout.Write(w.out.Bytes())
  1477  		// We no longer need the output, so drop the buffer.
  1478  		w.out = bytes.Buffer{}
  1479  		if w.err != nil {
  1480  			log.Printf("Failed: %v", w.err)
  1481  			t.failed = true
  1482  		}
  1483  	}
  1484  	pendingSpan.done()
  1485  	if t.failed && !t.keepGoing {
  1486  		fatalf("FAILED")
  1487  	}
  1488  
  1489  	if dt := nextTest; dt != nil {
  1490  		if t.lastHeading != dt.heading {
  1491  			t.lastHeading = dt.heading
  1492  			t.out(dt.heading)
  1493  		}
  1494  		if vflag > 0 {
  1495  			fmt.Printf("# go tool dist test -run=^%s$\n", dt.name)
  1496  		}
  1497  	}
  1498  }
  1499  
  1500  // hasParallelism is a copy of the function
  1501  // internal/testenv.HasParallelism, which can't be used here
  1502  // because cmd/dist can not import internal packages during bootstrap.
  1503  func (t *tester) hasParallelism() bool {
  1504  	switch goos {
  1505  	case "js", "wasip1":
  1506  		return false
  1507  	}
  1508  	return true
  1509  }
  1510  
  1511  func (t *tester) raceDetectorSupported() bool {
  1512  	if gohostos != goos {
  1513  		return false
  1514  	}
  1515  	if !t.cgoEnabled {
  1516  		return false
  1517  	}
  1518  	if !raceDetectorSupported(goos, goarch) {
  1519  		return false
  1520  	}
  1521  	// The race detector doesn't work on Alpine Linux:
  1522  	// golang.org/issue/14481
  1523  	if isAlpineLinux() {
  1524  		return false
  1525  	}
  1526  	// NetBSD support is unfinished.
  1527  	// golang.org/issue/26403
  1528  	if goos == "netbsd" {
  1529  		return false
  1530  	}
  1531  	return true
  1532  }
  1533  
  1534  func isAlpineLinux() bool {
  1535  	if runtime.GOOS != "linux" {
  1536  		return false
  1537  	}
  1538  	fi, err := os.Lstat("/etc/alpine-release")
  1539  	return err == nil && fi.Mode().IsRegular()
  1540  }
  1541  
  1542  func (t *tester) registerRaceTests() {
  1543  	hdr := "Testing race detector"
  1544  	t.registerTest(hdr,
  1545  		&goTest{
  1546  			variant:  "race",
  1547  			race:     true,
  1548  			runTests: "Output",
  1549  			pkg:      "runtime/race",
  1550  		})
  1551  	t.registerTest(hdr,
  1552  		&goTest{
  1553  			variant:  "race",
  1554  			race:     true,
  1555  			runTests: "TestParse|TestEcho|TestStdinCloseRace|TestClosedPipeRace|TestTypeRace|TestFdRace|TestFdReadRace|TestFileCloseRace",
  1556  			pkgs:     []string{"flag", "net", "os", "os/exec", "encoding/gob"},
  1557  		})
  1558  	// We don't want the following line, because it
  1559  	// slows down all.bash (by 10 seconds on my laptop).
  1560  	// The race builder should catch any error here, but doesn't.
  1561  	// TODO(iant): Figure out how to catch this.
  1562  	// t.registerTest(hdr, &goTest{variant: "race", race: true, runTests: "TestParallelTest", pkg: "cmd/go"})
  1563  	if t.cgoEnabled {
  1564  		// Building cmd/cgo/internal/test takes a long time.
  1565  		// There are already cgo-enabled packages being tested with the race detector.
  1566  		// We shouldn't need to redo all of cmd/cgo/internal/test too.
  1567  		// The race builder will take care of this.
  1568  		// t.registerTest(hdr, &goTest{variant: "race", race: true, env: []string{"GOTRACEBACK=2"}, pkg: "cmd/cgo/internal/test"})
  1569  	}
  1570  	if t.extLink() {
  1571  		// Test with external linking; see issue 9133.
  1572  		t.registerTest(hdr,
  1573  			&goTest{
  1574  				variant:  "race-external",
  1575  				race:     true,
  1576  				ldflags:  "-linkmode=external",
  1577  				runTests: "TestParse|TestEcho|TestStdinCloseRace",
  1578  				pkgs:     []string{"flag", "os/exec"},
  1579  			})
  1580  	}
  1581  }
  1582  
  1583  // cgoPackages is the standard packages that use cgo.
  1584  var cgoPackages = []string{
  1585  	"net",
  1586  	"os/user",
  1587  }
  1588  
  1589  var funcBenchmark = []byte("\nfunc Benchmark")
  1590  
  1591  // packageHasBenchmarks reports whether pkg has benchmarks.
  1592  // On any error, it conservatively returns true.
  1593  //
  1594  // This exists just to eliminate work on the builders, since compiling
  1595  // a test in race mode just to discover it has no benchmarks costs a
  1596  // second or two per package, and this function returns false for
  1597  // about 100 packages.
  1598  func (t *tester) packageHasBenchmarks(pkg string) bool {
  1599  	pkgDir := filepath.Join(goroot, "src", pkg)
  1600  	d, err := os.Open(pkgDir)
  1601  	if err != nil {
  1602  		return true // conservatively
  1603  	}
  1604  	defer d.Close()
  1605  	names, err := d.Readdirnames(-1)
  1606  	if err != nil {
  1607  		return true // conservatively
  1608  	}
  1609  	for _, name := range names {
  1610  		if !strings.HasSuffix(name, "_test.go") {
  1611  			continue
  1612  		}
  1613  		slurp, err := os.ReadFile(filepath.Join(pkgDir, name))
  1614  		if err != nil {
  1615  			return true // conservatively
  1616  		}
  1617  		if bytes.Contains(slurp, funcBenchmark) {
  1618  			return true
  1619  		}
  1620  	}
  1621  	return false
  1622  }
  1623  
  1624  // makeGOROOTUnwritable makes all $GOROOT files & directories non-writable to
  1625  // check that no tests accidentally write to $GOROOT.
  1626  func (t *tester) makeGOROOTUnwritable() (undo func()) {
  1627  	dir := os.Getenv("GOROOT")
  1628  	if dir == "" {
  1629  		panic("GOROOT not set")
  1630  	}
  1631  
  1632  	type pathMode struct {
  1633  		path string
  1634  		mode os.FileMode
  1635  	}
  1636  	var dirs []pathMode // in lexical order
  1637  
  1638  	undo = func() {
  1639  		for i := range dirs {
  1640  			os.Chmod(dirs[i].path, dirs[i].mode) // best effort
  1641  		}
  1642  	}
  1643  
  1644  	filepath.WalkDir(dir, func(path string, d fs.DirEntry, err error) error {
  1645  		if suffix := strings.TrimPrefix(path, dir+string(filepath.Separator)); suffix != "" {
  1646  			if suffix == ".git" {
  1647  				// Leave Git metadata in whatever state it was in. It may contain a lot
  1648  				// of files, and it is highly unlikely that a test will try to modify
  1649  				// anything within that directory.
  1650  				return filepath.SkipDir
  1651  			}
  1652  		}
  1653  		if err != nil {
  1654  			return nil
  1655  		}
  1656  
  1657  		info, err := d.Info()
  1658  		if err != nil {
  1659  			return nil
  1660  		}
  1661  
  1662  		mode := info.Mode()
  1663  		if mode&0222 != 0 && (mode.IsDir() || mode.IsRegular()) {
  1664  			dirs = append(dirs, pathMode{path, mode})
  1665  		}
  1666  		return nil
  1667  	})
  1668  
  1669  	// Run over list backward to chmod children before parents.
  1670  	for i := len(dirs) - 1; i >= 0; i-- {
  1671  		err := os.Chmod(dirs[i].path, dirs[i].mode&^0222)
  1672  		if err != nil {
  1673  			dirs = dirs[i:] // Only undo what we did so far.
  1674  			undo()
  1675  			fatalf("failed to make GOROOT read-only: %v", err)
  1676  		}
  1677  	}
  1678  
  1679  	return undo
  1680  }
  1681  
  1682  // raceDetectorSupported is a copy of the function
  1683  // internal/platform.RaceDetectorSupported, which can't be used here
  1684  // because cmd/dist can not import internal packages during bootstrap.
  1685  // The race detector only supports 48-bit VMA on arm64. But we don't have
  1686  // a good solution to check VMA size (see https://go.dev/issue/29948).
  1687  // raceDetectorSupported will always return true for arm64. But race
  1688  // detector tests may abort on non 48-bit VMA configuration, the tests
  1689  // will be marked as "skipped" in this case.
  1690  func raceDetectorSupported(goos, goarch string) bool {
  1691  	switch goos {
  1692  	case "linux":
  1693  		return goarch == "amd64" || goarch == "arm64" || goarch == "loong64" || goarch == "ppc64le" || goarch == "riscv64" || goarch == "s390x"
  1694  	case "darwin":
  1695  		return goarch == "amd64" || goarch == "arm64"
  1696  	case "freebsd", "netbsd", "windows":
  1697  		return goarch == "amd64"
  1698  	default:
  1699  		return false
  1700  	}
  1701  }
  1702  
  1703  // fips140Supported is a copy of the function
  1704  // internal/platform.FIPS140Supported, which can't be used here
  1705  // because cmd/dist can not import internal packages during bootstrap.
  1706  func fips140Supported(goos, goarch string) bool {
  1707  	switch {
  1708  	case goarch == "wasm",
  1709  		goos == "windows" && goarch == "386",
  1710  		goos == "openbsd",
  1711  		goos == "aix":
  1712  		return false
  1713  	}
  1714  	return true
  1715  }
  1716  
  1717  // buildModeSupported is a copy of the function
  1718  // internal/platform.BuildModeSupported, which can't be used here
  1719  // because cmd/dist can not import internal packages during bootstrap.
  1720  func buildModeSupported(compiler, buildmode, goos, goarch string) bool {
  1721  	if compiler == "gccgo" {
  1722  		return true
  1723  	}
  1724  
  1725  	platform := goos + "/" + goarch
  1726  
  1727  	switch buildmode {
  1728  	case "archive":
  1729  		return true
  1730  
  1731  	case "c-archive":
  1732  		switch goos {
  1733  		case "aix", "darwin", "ios", "windows":
  1734  			return true
  1735  		case "linux":
  1736  			switch goarch {
  1737  			case "386", "amd64", "arm", "armbe", "arm64", "arm64be", "loong64", "ppc64", "ppc64le", "riscv64", "s390x":
  1738  				return true
  1739  			default:
  1740  				// Other targets do not support -shared,
  1741  				// per ParseFlags in
  1742  				// cmd/compile/internal/base/flag.go.
  1743  				// For c-archive the Go tool passes -shared,
  1744  				// so that the result is suitable for inclusion
  1745  				// in a PIE or shared library.
  1746  				return false
  1747  			}
  1748  		case "freebsd":
  1749  			return goarch == "amd64"
  1750  		}
  1751  		return false
  1752  
  1753  	case "c-shared":
  1754  		switch platform {
  1755  		case "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/386", "linux/ppc64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
  1756  			"android/amd64", "android/arm", "android/arm64", "android/386",
  1757  			"freebsd/amd64",
  1758  			"darwin/amd64", "darwin/arm64",
  1759  			"windows/amd64", "windows/386", "windows/arm64",
  1760  			"wasip1/wasm":
  1761  			return true
  1762  		}
  1763  		return false
  1764  
  1765  	case "default":
  1766  		return true
  1767  
  1768  	case "exe":
  1769  		return true
  1770  
  1771  	case "pie":
  1772  		switch platform {
  1773  		case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/loong64", "linux/ppc64", "linux/ppc64le", "linux/riscv64", "linux/s390x",
  1774  			"android/amd64", "android/arm", "android/arm64", "android/386",
  1775  			"freebsd/amd64",
  1776  			"darwin/amd64", "darwin/arm64",
  1777  			"ios/amd64", "ios/arm64",
  1778  			"aix/ppc64",
  1779  			"openbsd/amd64", "openbsd/arm64",
  1780  			"windows/386", "windows/amd64", "windows/arm64":
  1781  			return true
  1782  		}
  1783  		return false
  1784  
  1785  	case "shared":
  1786  		switch platform {
  1787  		case "linux/386", "linux/amd64", "linux/arm", "linux/arm64", "linux/ppc64", "linux/ppc64le", "linux/s390x":
  1788  			return true
  1789  		}
  1790  		return false
  1791  
  1792  	case "plugin":
  1793  		switch platform {
  1794  		case "linux/amd64", "linux/arm", "linux/arm64", "linux/386", "linux/loong64", "linux/riscv64", "linux/s390x", "linux/ppc64", "linux/ppc64le",
  1795  			"android/amd64", "android/386",
  1796  			"darwin/amd64", "darwin/arm64",
  1797  			"freebsd/amd64":
  1798  			return true
  1799  		}
  1800  		return false
  1801  
  1802  	default:
  1803  		return false
  1804  	}
  1805  }
  1806  
  1807  // isUnsupportedVMASize reports whether the failure is caused by an unsupported
  1808  // VMA for the race detector (for example, running the race detector on an
  1809  // arm64 machine configured with 39-bit VMA).
  1810  func isUnsupportedVMASize(w *work) bool {
  1811  	unsupportedVMA := []byte("unsupported VMA range")
  1812  	return strings.Contains(w.dt.name, ":race") && bytes.Contains(w.out.Bytes(), unsupportedVMA)
  1813  }
  1814  
  1815  // isEnvSet reports whether the environment variable evar is
  1816  // set in the environment.
  1817  func isEnvSet(evar string) bool {
  1818  	evarEq := evar + "="
  1819  	for _, e := range os.Environ() {
  1820  		if strings.HasPrefix(e, evarEq) {
  1821  			return true
  1822  		}
  1823  	}
  1824  	return false
  1825  }
  1826  
  1827  func (t *tester) fips140Supported() bool {
  1828  	if !fips140Supported(goos, goarch) {
  1829  		return false
  1830  	}
  1831  
  1832  	// Keep the platform checks below in sync with crypto/internal/fips140.Supported.
  1833  	// We don't test with the purego tag, so no need to check it.
  1834  
  1835  	// Use GOFIPS140 or GOEXPERIMENT=boringcrypto, but not both.
  1836  	if strings.Contains(goexperiment, "boringcrypto") {
  1837  		return false
  1838  	}
  1839  
  1840  	// For now, FIPS+ASAN doesn't need to work.
  1841  	// If this is made to work, also re-enable the test in check_test.go.
  1842  	if t.asan {
  1843  		return false
  1844  	}
  1845  
  1846  	return true
  1847  }
  1848  
  1849  // fips140Versions returns the list of versions available in lib/fips140.
  1850  func fips140Versions() []string {
  1851  	var versions []string
  1852  	zips, err := filepath.Glob(filepath.Join(goroot, "lib/fips140/*.zip"))
  1853  	if err != nil {
  1854  		fatalf("%v", err)
  1855  	}
  1856  	for _, zip := range zips {
  1857  		versions = append(versions, strings.TrimSuffix(filepath.Base(zip), ".zip"))
  1858  	}
  1859  	return versions
  1860  }
  1861  
  1862  // goexperiments returns the GOEXPERIMENT value to use
  1863  // when running a test with the given experiments enabled.
  1864  //
  1865  // It preserves any existing GOEXPERIMENTs.
  1866  func goexperiments(exps ...string) string {
  1867  	if len(exps) == 0 {
  1868  		return goexperiment
  1869  	}
  1870  	existing := goexperiment
  1871  	if existing != "" {
  1872  		existing += ","
  1873  	}
  1874  	return existing + strings.Join(exps, ",")
  1875  
  1876  }
  1877  

View as plain text