// Copyright 2017 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. //go:build linux || (freebsd && amd64) package sanitizers_test import ( "fmt" "internal/platform" "internal/testenv" "os" "strings" "testing" ) func TestShared(t *testing.T) { testenv.MustHaveGoBuild(t) testenv.MustHaveCGO(t) testenv.MustHaveBuildMode(t, "c-shared") t.Parallel() requireOvercommit(t) GOOS, err := goEnv("GOOS") if err != nil { t.Fatal(err) } GOARCH, err := goEnv("GOARCH") if err != nil { t.Fatal(err) } libExt := "so" if GOOS == "darwin" { libExt = "dylib" } cases := []struct { src string sanitizer string }{ { src: "msan_shared.go", sanitizer: "memory", }, { src: "tsan_shared.go", sanitizer: "thread", }, } for _, tc := range cases { tc := tc name := strings.TrimSuffix(tc.src, ".go") //The memory sanitizer tests require support for the -msan option. if tc.sanitizer == "memory" && !platform.MSanSupported(GOOS, GOARCH) { t.Logf("skipping %s test on %s/%s; -msan option is not supported.", name, GOOS, GOARCH) continue } if tc.sanitizer == "thread" && !compilerRequiredTsanVersion(GOOS, GOARCH) { t.Logf("skipping %s test on %s/%s; compiler version too old for -tsan.", name, GOOS, GOARCH) continue } t.Run(name, func(t *testing.T) { t.Parallel() config := configure(tc.sanitizer) config.skipIfCSanitizerBroken(t) dir := newTempDir(t) defer dir.RemoveAll(t) lib := dir.Join(fmt.Sprintf("lib%s.%s", name, libExt)) mustRun(t, config.goCmd("build", "-buildmode=c-shared", "-o", lib, srcPath(tc.src))) cSrc := dir.Join("main.c") if err := os.WriteFile(cSrc, cMain, 0600); err != nil { t.Fatalf("failed to write C source file: %v", err) } dstBin := dir.Join(name) cmd, err := cc(config.cFlags...) if err != nil { t.Fatal(err) } cmd.Args = append(cmd.Args, config.ldFlags...) cmd.Args = append(cmd.Args, "-o", dstBin, cSrc, lib) mustRun(t, cmd) cmd = hangProneCmd(dstBin) replaceEnv(cmd, "LD_LIBRARY_PATH", ".") mustRun(t, cmd) }) } }