1
2
3
4
5
6
7 package sanitizers_test
8
9 import (
10 "internal/platform"
11 "internal/testenv"
12 "strings"
13 "testing"
14 )
15
16 func TestLSAN(t *testing.T) {
17 config := mustHaveLSAN(t)
18
19 t.Parallel()
20 mustRun(t, config.goCmd("build", "std"))
21
22 cases := []struct {
23 src string
24 leakError string
25 errorLocation string
26 }{
27 {src: "lsan1.go", leakError: "detected memory leaks", errorLocation: "lsan1.go:11"},
28 {src: "lsan2.go"},
29 {src: "lsan3.go"},
30 }
31 for _, tc := range cases {
32 name := strings.TrimSuffix(tc.src, ".go")
33 t.Run(name, func(t *testing.T) {
34 t.Parallel()
35
36 dir := newTempDir(t)
37 defer dir.RemoveAll(t)
38
39 outPath := dir.Join(name)
40 mustRun(t, config.goCmd("build", "-o", outPath, srcPath(tc.src)))
41
42 cmd := hangProneCmd(outPath)
43 if tc.leakError == "" {
44 mustRun(t, cmd)
45 } else {
46 outb, err := cmd.CombinedOutput()
47 out := string(outb)
48 if err != nil || len(out) > 0 {
49 t.Logf("%s\n%v\n%s", cmd, err, out)
50 }
51 if err != nil && strings.Contains(out, tc.leakError) {
52
53
54
55 const noSymbolizer = "external symbolizer"
56 if tc.errorLocation != "" &&
57 !strings.Contains(out, tc.errorLocation) &&
58 !strings.Contains(out, noSymbolizer) &&
59 compilerSupportsLocation() {
60
61 t.Errorf("output does not contain expected location of the error %q", tc.errorLocation)
62 }
63 } else {
64 t.Errorf("output does not contain expected leak error %q", tc.leakError)
65 }
66
67
68 cmd = hangProneCmd(outPath)
69 replaceEnv(cmd, "ASAN_OPTIONS", "detect_leaks=0")
70 mustRun(t, cmd)
71 }
72 })
73 }
74 }
75
76 func mustHaveLSAN(t *testing.T) *config {
77 testenv.MustHaveGoBuild(t)
78 testenv.MustHaveCGO(t)
79 goos, err := goEnv("GOOS")
80 if err != nil {
81 t.Fatal(err)
82 }
83 goarch, err := goEnv("GOARCH")
84 if err != nil {
85 t.Fatal(err)
86 }
87
88 if !platform.ASanSupported(goos, goarch) {
89 t.Skipf("skipping on %s/%s; -asan option is not supported.", goos, goarch)
90 }
91
92 if !compilerRequiredLsanVersion(goos, goarch) {
93 t.Skipf("skipping on %s/%s: too old version of compiler", goos, goarch)
94 }
95
96 requireOvercommit(t)
97
98 config := configure("leak")
99 config.skipIfCSanitizerBroken(t)
100
101 return config
102 }
103
View as plain text