Source file src/cmd/cgo/internal/testsanitizers/cshared_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  	"fmt"
    11  	"internal/platform"
    12  	"internal/testenv"
    13  	"os"
    14  	"os/exec"
    15  	"strings"
    16  	"testing"
    17  )
    18  
    19  func TestShared(t *testing.T) {
    20  	testenv.MustHaveGoBuild(t)
    21  	testenv.MustHaveCGO(t)
    22  	testenv.MustHaveBuildMode(t, "c-shared")
    23  
    24  	t.Parallel()
    25  	requireOvercommit(t)
    26  
    27  	GOOS, err := goEnv("GOOS")
    28  	if err != nil {
    29  		t.Fatal(err)
    30  	}
    31  
    32  	GOARCH, err := goEnv("GOARCH")
    33  	if err != nil {
    34  		t.Fatal(err)
    35  	}
    36  
    37  	libExt := "so"
    38  	if GOOS == "darwin" {
    39  		libExt = "dylib"
    40  	}
    41  
    42  	cases := []struct {
    43  		src       string
    44  		sanitizer string
    45  	}{
    46  		{
    47  			src:       "msan_shared.go",
    48  			sanitizer: "memory",
    49  		},
    50  		{
    51  			src:       "tsan_shared.go",
    52  			sanitizer: "thread",
    53  		},
    54  	}
    55  
    56  	for _, tc := range cases {
    57  		tc := tc
    58  		name := strings.TrimSuffix(tc.src, ".go")
    59  		//The memory sanitizer tests require support for the -msan option.
    60  		if tc.sanitizer == "memory" && !platform.MSanSupported(GOOS, GOARCH) {
    61  			t.Logf("skipping %s test on %s/%s; -msan option is not supported.", name, GOOS, GOARCH)
    62  			continue
    63  		}
    64  		if tc.sanitizer == "thread" && !compilerRequiredTsanVersion(GOOS, GOARCH) {
    65  			t.Logf("skipping %s test on %s/%s; compiler version too old for -tsan.", name, GOOS, GOARCH)
    66  			continue
    67  		}
    68  
    69  		t.Run(name, func(t *testing.T) {
    70  			t.Parallel()
    71  			config := configure(tc.sanitizer)
    72  			config.skipIfCSanitizerBroken(t)
    73  
    74  			dir := newTempDir(t)
    75  			defer dir.RemoveAll(t)
    76  
    77  			lib := dir.Join(fmt.Sprintf("lib%s.%s", name, libExt))
    78  			mustRun(t, config.goCmd("build", "-buildmode=c-shared", "-o", lib, srcPath(tc.src)))
    79  
    80  			cSrc := dir.Join("main.c")
    81  			if err := os.WriteFile(cSrc, cMain, 0600); err != nil {
    82  				t.Fatalf("failed to write C source file: %v", err)
    83  			}
    84  
    85  			dstBin := dir.Join(name)
    86  			cmd, err := cc(config.cFlags...)
    87  			if err != nil {
    88  				t.Fatal(err)
    89  			}
    90  			cmd.Args = append(cmd.Args, config.ldFlags...)
    91  			cmd.Args = append(cmd.Args, "-o", dstBin, cSrc, lib)
    92  			mustRun(t, cmd)
    93  
    94  			cmdArgs := []string{dstBin}
    95  			if tc.sanitizer == "thread" && GOOS == "linux" {
    96  				// Disable ASLR for TSAN. See https://go.dev/issue/59418.
    97  				out, err := exec.Command("uname", "-m").Output()
    98  				if err != nil {
    99  					t.Fatalf("failed to run `uname -m`: %v", err)
   100  				}
   101  				arch := strings.TrimSpace(string(out))
   102  				if _, err := exec.Command("setarch", arch, "-R", "true").Output(); err != nil {
   103  					// Some systems don't have permission to run `setarch`.
   104  					// See https://go.dev/issue/70463.
   105  					t.Logf("failed to run `setarch %s -R true`: %v", arch, err)
   106  				} else {
   107  					cmdArgs = []string{"setarch", arch, "-R", dstBin}
   108  				}
   109  			}
   110  			cmd = hangProneCmd(cmdArgs[0], cmdArgs[1:]...)
   111  			replaceEnv(cmd, "LD_LIBRARY_PATH", ".")
   112  			mustRun(t, cmd)
   113  		})
   114  	}
   115  }
   116  

View as plain text