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  		{src: "tsan_tracebackctxt", needsRuntime: true}, // Subdirectory
    60  	}
    61  	for _, tc := range cases {
    62  		tc := tc
    63  		name := strings.TrimSuffix(tc.src, ".go")
    64  		t.Run(name, func(t *testing.T) {
    65  			t.Parallel()
    66  
    67  			dir := newTempDir(t)
    68  			defer dir.RemoveAll(t)
    69  
    70  			outPath := dir.Join(name)
    71  			mustRun(t, config.goCmd("build", "-o", outPath, "./"+srcPath(tc.src)))
    72  
    73  			cmdArgs := []string{outPath}
    74  			if goos == "linux" {
    75  				// Disable ASLR for TSAN. See https://go.dev/issue/59418.
    76  				out, err := exec.Command("uname", "-m").Output()
    77  				if err != nil {
    78  					t.Fatalf("failed to run `uname -m`: %v", err)
    79  				}
    80  				arch := strings.TrimSpace(string(out))
    81  				if _, err := exec.Command("setarch", arch, "-R", "true").Output(); err != nil {
    82  					// Some systems don't have permission to run `setarch`.
    83  					// See https://go.dev/issue/70463.
    84  					t.Logf("failed to run `setarch %s -R true`: %v", arch, err)
    85  				} else {
    86  					cmdArgs = []string{"setarch", arch, "-R", outPath}
    87  				}
    88  			}
    89  			cmd := hangProneCmd(cmdArgs[0], cmdArgs[1:]...)
    90  			if tc.needsRuntime {
    91  				config.skipIfRuntimeIncompatible(t)
    92  			}
    93  			// If we don't see halt_on_error, the program
    94  			// will only exit non-zero if we call C.exit.
    95  			cmd.Env = append(cmd.Environ(), "TSAN_OPTIONS=halt_on_error=1")
    96  			mustRun(t, cmd)
    97  		})
    98  	}
    99  }
   100  

View as plain text