annotate libgo/misc/cgo/testsanitizers/cc_test.go @ 145:1830386684a0

gcc-9.2.0
author anatofuz
date Thu, 13 Feb 2020 11:34:05 +0900
parents 84e7813d76e9
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
131
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
1 // Copyright 2017 The Go Authors. All rights reserved.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
2 // Use of this source code is governed by a BSD-style
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
3 // license that can be found in the LICENSE file.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
4
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
5 // sanitizers_test checks the use of Go with sanitizers like msan, asan, etc.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
6 // See https://github.com/google/sanitizers.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
7 package sanitizers_test
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
8
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
9 import (
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
10 "bytes"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
11 "encoding/json"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
12 "errors"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
13 "fmt"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
14 "io/ioutil"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
15 "os"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
16 "os/exec"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
17 "path/filepath"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
18 "regexp"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
19 "strconv"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
20 "strings"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
21 "sync"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
22 "syscall"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
23 "testing"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
24 "unicode"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
25 )
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
26
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
27 var overcommit struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
28 sync.Once
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
29 value int
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
30 err error
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
31 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
32
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
33 // requireOvercommit skips t if the kernel does not allow overcommit.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
34 func requireOvercommit(t *testing.T) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
35 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
36
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
37 overcommit.Once.Do(func() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
38 var out []byte
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
39 out, overcommit.err = ioutil.ReadFile("/proc/sys/vm/overcommit_memory")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
40 if overcommit.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
41 return
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
42 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
43 overcommit.value, overcommit.err = strconv.Atoi(string(bytes.TrimSpace(out)))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
44 })
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
45
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
46 if overcommit.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
47 t.Skipf("couldn't determine vm.overcommit_memory (%v); assuming no overcommit", overcommit.err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
48 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
49 if overcommit.value == 2 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
50 t.Skip("vm.overcommit_memory=2")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
51 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
52 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
53
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
54 var env struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
55 sync.Once
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
56 m map[string]string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
57 err error
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
58 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
59
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
60 // goEnv returns the output of $(go env) as a map.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
61 func goEnv(key string) (string, error) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
62 env.Once.Do(func() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
63 var out []byte
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
64 out, env.err = exec.Command("go", "env", "-json").Output()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
65 if env.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
66 return
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
67 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
68
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
69 env.m = make(map[string]string)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
70 env.err = json.Unmarshal(out, &env.m)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
71 })
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
72 if env.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
73 return "", env.err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
74 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
75
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
76 v, ok := env.m[key]
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
77 if !ok {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
78 return "", fmt.Errorf("`go env`: no entry for %v", key)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
79 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
80 return v, nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
81 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
82
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
83 // replaceEnv sets the key environment variable to value in cmd.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
84 func replaceEnv(cmd *exec.Cmd, key, value string) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
85 if cmd.Env == nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
86 cmd.Env = os.Environ()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
87 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
88 cmd.Env = append(cmd.Env, key+"="+value)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
89 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
90
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
91 // mustRun executes t and fails cmd with a well-formatted message if it fails.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
92 func mustRun(t *testing.T, cmd *exec.Cmd) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
93 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
94 out, err := cmd.CombinedOutput()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
95 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
96 t.Fatalf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
97 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
98 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
99
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
100 // cc returns a cmd that executes `$(go env CC) $(go env GOGCCFLAGS) $args`.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
101 func cc(args ...string) (*exec.Cmd, error) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
102 CC, err := goEnv("CC")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
103 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
104 return nil, err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
105 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
106
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
107 GOGCCFLAGS, err := goEnv("GOGCCFLAGS")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
108 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
109 return nil, err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
110 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
111
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
112 // Split GOGCCFLAGS, respecting quoting.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
113 //
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
114 // TODO(bcmills): This code also appears in
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
115 // misc/cgo/testcarchive/carchive_test.go, and perhaps ought to go in
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
116 // src/cmd/dist/test.go as well. Figure out where to put it so that it can be
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
117 // shared.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
118 var flags []string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
119 quote := '\000'
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
120 start := 0
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
121 lastSpace := true
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
122 backslash := false
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
123 for i, c := range GOGCCFLAGS {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
124 if quote == '\000' && unicode.IsSpace(c) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
125 if !lastSpace {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
126 flags = append(flags, GOGCCFLAGS[start:i])
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
127 lastSpace = true
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
128 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
129 } else {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
130 if lastSpace {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
131 start = i
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
132 lastSpace = false
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
133 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
134 if quote == '\000' && !backslash && (c == '"' || c == '\'') {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
135 quote = c
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
136 backslash = false
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
137 } else if !backslash && quote == c {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
138 quote = '\000'
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
139 } else if (quote == '\000' || quote == '"') && !backslash && c == '\\' {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
140 backslash = true
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
141 } else {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
142 backslash = false
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
143 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
144 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
145 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
146 if !lastSpace {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
147 flags = append(flags, GOGCCFLAGS[start:])
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
148 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
149
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
150 cmd := exec.Command(CC, flags...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
151 cmd.Args = append(cmd.Args, args...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
152 return cmd, nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
153 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
154
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
155 type version struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
156 name string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
157 major, minor int
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
158 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
159
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
160 var compiler struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
161 sync.Once
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
162 version
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
163 err error
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
164 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
165
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
166 // compilerVersion detects the version of $(go env CC).
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
167 //
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
168 // It returns a non-nil error if the compiler matches a known version schema but
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
169 // the version could not be parsed, or if $(go env CC) could not be determined.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
170 func compilerVersion() (version, error) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
171 compiler.Once.Do(func() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
172 compiler.err = func() error {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
173 compiler.name = "unknown"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
174
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
175 cmd, err := cc("--version")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
176 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
177 return err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
178 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
179 out, err := cmd.Output()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
180 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
181 // Compiler does not support "--version" flag: not Clang or GCC.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
182 return nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
183 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
184
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
185 var match [][]byte
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
186 if bytes.HasPrefix(out, []byte("gcc")) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
187 compiler.name = "gcc"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
188
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
189 cmd, err := cc("-dumpversion")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
190 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
191 return err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
192 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
193 out, err := cmd.Output()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
194 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
195 // gcc, but does not support gcc's "-dumpversion" flag?!
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
196 return err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
197 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
198 gccRE := regexp.MustCompile(`(\d+)\.(\d+)`)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
199 match = gccRE.FindSubmatch(out)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
200 } else {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
201 clangRE := regexp.MustCompile(`clang version (\d+)\.(\d+)`)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
202 if match = clangRE.FindSubmatch(out); len(match) > 0 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
203 compiler.name = "clang"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
204 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
205 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
206
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
207 if len(match) < 3 {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
208 return nil // "unknown"
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
209 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
210 if compiler.major, err = strconv.Atoi(string(match[1])); err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
211 return err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
212 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
213 if compiler.minor, err = strconv.Atoi(string(match[2])); err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
214 return err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
215 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
216 return nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
217 }()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
218 })
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
219 return compiler.version, compiler.err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
220 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
221
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
222 type compilerCheck struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
223 once sync.Once
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
224 err error
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
225 skip bool // If true, skip with err instead of failing with it.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
226 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
227
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
228 type config struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
229 sanitizer string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
230
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
231 cFlags, ldFlags, goFlags []string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
232
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
233 sanitizerCheck, runtimeCheck compilerCheck
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
234 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
235
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
236 var configs struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
237 sync.Mutex
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
238 m map[string]*config
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
239 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
240
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
241 // configure returns the configuration for the given sanitizer.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
242 func configure(sanitizer string) *config {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
243 configs.Lock()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
244 defer configs.Unlock()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
245 if c, ok := configs.m[sanitizer]; ok {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
246 return c
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
247 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
248
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
249 c := &config{
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
250 sanitizer: sanitizer,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
251 cFlags: []string{"-fsanitize=" + sanitizer},
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
252 ldFlags: []string{"-fsanitize=" + sanitizer},
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
253 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
254
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
255 if testing.Verbose() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
256 c.goFlags = append(c.goFlags, "-x")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
257 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
258
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
259 switch sanitizer {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
260 case "memory":
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
261 c.goFlags = append(c.goFlags, "-msan")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
262
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
263 case "thread":
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
264 c.goFlags = append(c.goFlags, "--installsuffix=tsan")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
265 compiler, _ := compilerVersion()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
266 if compiler.name == "gcc" {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
267 c.cFlags = append(c.cFlags, "-fPIC")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
268 c.ldFlags = append(c.ldFlags, "-fPIC", "-static-libtsan")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
269 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
270
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
271 default:
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
272 panic(fmt.Sprintf("unrecognized sanitizer: %q", sanitizer))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
273 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
274
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
275 if configs.m == nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
276 configs.m = make(map[string]*config)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
277 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
278 configs.m[sanitizer] = c
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
279 return c
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
280 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
281
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
282 // goCmd returns a Cmd that executes "go $subcommand $args" with appropriate
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
283 // additional flags and environment.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
284 func (c *config) goCmd(subcommand string, args ...string) *exec.Cmd {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
285 cmd := exec.Command("go", subcommand)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
286 cmd.Args = append(cmd.Args, c.goFlags...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
287 cmd.Args = append(cmd.Args, args...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
288 replaceEnv(cmd, "CGO_CFLAGS", strings.Join(c.cFlags, " "))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
289 replaceEnv(cmd, "CGO_LDFLAGS", strings.Join(c.ldFlags, " "))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
290 return cmd
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
291 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
292
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
293 // skipIfCSanitizerBroken skips t if the C compiler does not produce working
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
294 // binaries as configured.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
295 func (c *config) skipIfCSanitizerBroken(t *testing.T) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
296 check := &c.sanitizerCheck
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
297 check.once.Do(func() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
298 check.skip, check.err = c.checkCSanitizer()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
299 })
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
300 if check.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
301 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
302 if check.skip {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
303 t.Skip(check.err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
304 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
305 t.Fatal(check.err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
306 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
307 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
308
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
309 var cMain = []byte(`
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
310 int main() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
311 return 0;
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
312 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
313 `)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
314
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
315 func (c *config) checkCSanitizer() (skip bool, err error) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
316 dir, err := ioutil.TempDir("", c.sanitizer)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
317 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
318 return false, fmt.Errorf("failed to create temp directory: %v", err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
319 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
320 defer os.RemoveAll(dir)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
321
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
322 src := filepath.Join(dir, "return0.c")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
323 if err := ioutil.WriteFile(src, cMain, 0600); err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
324 return false, fmt.Errorf("failed to write C source file: %v", err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
325 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
326
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
327 dst := filepath.Join(dir, "return0")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
328 cmd, err := cc(c.cFlags...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
329 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
330 return false, err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
331 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
332 cmd.Args = append(cmd.Args, c.ldFlags...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
333 cmd.Args = append(cmd.Args, "-o", dst, src)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
334 out, err := cmd.CombinedOutput()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
335 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
336 if bytes.Contains(out, []byte("-fsanitize")) &&
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
337 (bytes.Contains(out, []byte("unrecognized")) ||
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
338 bytes.Contains(out, []byte("unsupported"))) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
339 return true, errors.New(string(out))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
340 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
341 return true, fmt.Errorf("%#q failed: %v\n%s", strings.Join(cmd.Args, " "), err, out)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
342 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
343
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
344 if out, err := exec.Command(dst).CombinedOutput(); err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
345 if os.IsNotExist(err) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
346 return true, fmt.Errorf("%#q failed to produce executable: %v", strings.Join(cmd.Args, " "), err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
347 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
348 snippet := bytes.SplitN(out, []byte{'\n'}, 2)[0]
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
349 return true, fmt.Errorf("%#q generated broken executable: %v\n%s", strings.Join(cmd.Args, " "), err, snippet)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
350 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
351
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
352 return false, nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
353 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
354
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
355 // skipIfRuntimeIncompatible skips t if the Go runtime is suspected not to work
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
356 // with cgo as configured.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
357 func (c *config) skipIfRuntimeIncompatible(t *testing.T) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
358 check := &c.runtimeCheck
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
359 check.once.Do(func() {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
360 check.skip, check.err = c.checkRuntime()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
361 })
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
362 if check.err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
363 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
364 if check.skip {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
365 t.Skip(check.err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
366 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
367 t.Fatal(check.err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
368 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
369 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
370
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
371 func (c *config) checkRuntime() (skip bool, err error) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
372 if c.sanitizer != "thread" {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
373 return false, nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
374 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
375
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
376 // libcgo.h sets CGO_TSAN if it detects TSAN support in the C compiler.
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
377 // Dump the preprocessor defines to check that works.
131
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
378 // (Sometimes it doesn't: see https://golang.org/issue/15983.)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
379 cmd, err := cc(c.cFlags...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
380 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
381 return false, err
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
382 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
383 cmd.Args = append(cmd.Args, "-dM", "-E", "../../../src/runtime/cgo/libcgo.h")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
384 cmdStr := strings.Join(cmd.Args, " ")
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
385 out, err := cmd.CombinedOutput()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
386 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
387 return false, fmt.Errorf("%#q exited with %v\n%s", cmdStr, err, out)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
388 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
389 if !bytes.Contains(out, []byte("#define CGO_TSAN")) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
390 return true, fmt.Errorf("%#q did not define CGO_TSAN", cmdStr)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
391 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
392 return false, nil
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
393 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
394
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
395 // srcPath returns the path to the given file relative to this test's source tree.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
396 func srcPath(path string) string {
145
1830386684a0 gcc-9.2.0
anatofuz
parents: 131
diff changeset
397 return filepath.Join("testdata", path)
131
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
398 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
399
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
400 // A tempDir manages a temporary directory within a test.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
401 type tempDir struct {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
402 base string
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
403 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
404
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
405 func (d *tempDir) RemoveAll(t *testing.T) {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
406 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
407 if d.base == "" {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
408 return
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
409 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
410 if err := os.RemoveAll(d.base); err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
411 t.Fatalf("Failed to remove temp dir: %v", err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
412 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
413 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
414
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
415 func (d *tempDir) Join(name string) string {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
416 return filepath.Join(d.base, name)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
417 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
418
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
419 func newTempDir(t *testing.T) *tempDir {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
420 t.Helper()
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
421 dir, err := ioutil.TempDir("", filepath.Dir(t.Name()))
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
422 if err != nil {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
423 t.Fatalf("Failed to create temp dir: %v", err)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
424 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
425 return &tempDir{base: dir}
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
426 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
427
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
428 // hangProneCmd returns an exec.Cmd for a command that is likely to hang.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
429 //
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
430 // If one of these tests hangs, the caller is likely to kill the test process
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
431 // using SIGINT, which will be sent to all of the processes in the test's group.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
432 // Unfortunately, TSAN in particular is prone to dropping signals, so the SIGINT
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
433 // may terminate the test binary but leave the subprocess running. hangProneCmd
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
434 // configures subprocess to receive SIGKILL instead to ensure that it won't
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
435 // leak.
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
436 func hangProneCmd(name string, arg ...string) *exec.Cmd {
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
437 cmd := exec.Command(name, arg...)
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
438 cmd.SysProcAttr = &syscall.SysProcAttr{
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
439 Pdeathsig: syscall.SIGKILL,
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
440 }
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
441 return cmd
84e7813d76e9 gcc-8.2
mir3636
parents:
diff changeset
442 }