Source file src/cmd/cgo/internal/testsanitizers/tsan_test.go

     1  // Copyright 2017 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  //go:build linux || (freebsd && amd64)
     6  
     7  package sanitizers_test
     8  
     9  import (
    10  	"internal/testenv"
    11  	"os/exec"
    12  	"strings"
    13  	"testing"
    14  )
    15  
    16  func TestTSAN(t *testing.T) {
    17  	testenv.MustHaveGoBuild(t)
    18  	testenv.MustHaveCGO(t)
    19  
    20  	goos, err := goEnv("GOOS")
    21  	if err != nil {
    22  		t.Fatal(err)
    23  	}
    24  	goarch, err := goEnv("GOARCH")
    25  	if err != nil {
    26  		t.Fatal(err)
    27  	}
    28  	// The tsan tests require support for the -tsan option.
    29  	if !compilerRequiredTsanVersion(goos, goarch) {
    30  		t.Skipf("skipping on %s/%s; compiler version for -tsan option is too old.", goos, goarch)
    31  	}
    32  
    33  	t.Parallel()
    34  	requireOvercommit(t)
    35  	config := configure("thread")
    36  	config.skipIfCSanitizerBroken(t)
    37  
    38  	mustRun(t, config.goCmd("build", "std"))
    39  
    40  	cases := []struct {
    41  		src          string
    42  		needsRuntime bool
    43  	}{
    44  		{src: "tsan.go"},
    45  		{src: "tsan2.go"},
    46  		{src: "tsan3.go"},
    47  		{src: "tsan4.go"},
    48  		{src: "tsan5.go", needsRuntime: true},
    49  		{src: "tsan6.go", needsRuntime: true},
    50  		{src: "tsan7.go", needsRuntime: true},
    51  		{src: "tsan8.go"},
    52  		{src: "tsan9.go"},
    53  		{src: "tsan10.go", needsRuntime: true},
    54  		{src: "tsan11.go", needsRuntime: true},
    55  		{src: "tsan12.go", needsRuntime: true},
    56  		{src: "tsan13.go", needsRuntime: true},
    57  		{src: "tsan14.go", needsRuntime: true},
    58  		{src: "tsan15.go", needsRuntime: true},
    59  	}
    60  	for _, tc := range cases {
    61  		tc := tc
    62  		name := strings.TrimSuffix(tc.src, ".go")
    63  		t.Run(name, func(t *testing.T) {
    64  			t.Parallel()
    65  
    66  			dir := newTempDir(t)
    67  			defer dir.RemoveAll(t)
    68  
    69  			outPath := dir.Join(name)
    70  			mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
    71  
    72  			cmdArgs := []string{outPath}
    73  			if goos == "linux" {
    74  				// Disable ASLR for TSAN. See https://go.dev/issue/59418.
    75  				out, err := exec.Command("uname", "-m").Output()
    76  				if err != nil {
    77  					t.Fatalf("failed to run `uname -m`: %v", err)
    78  				}
    79  				arch := strings.TrimSpace(string(out))
    80  				if _, err := exec.Command("setarch", arch, "-R", "true").Output(); err != nil {
    81  					// Some systems don't have permission to run `setarch`.
    82  					// See https://go.dev/issue/70463.
    83  					t.Logf("failed to run `setarch %s -R true`: %v", arch, err)
    84  				} else {
    85  					cmdArgs = []string{"setarch", arch, "-R", outPath}
    86  				}
    87  			}
    88  			cmd := hangProneCmd(cmdArgs[0], cmdArgs[1:]...)
    89  			if tc.needsRuntime {
    90  				config.skipIfRuntimeIncompatible(t)
    91  			}
    92  			// If we don't see halt_on_error, the program
    93  			// will only exit non-zero if we call C.exit.
    94  			cmd.Env = append(cmd.Environ(), "TSAN_OPTIONS=halt_on_error=1")
    95  			mustRun(t, cmd)
    96  		})
    97  	}
    98  }
    99  

View as plain text