Source file
src/runtime/race/output_test.go
1
2
3
4
5
6
7
8 package race_test
9
10 import (
11 "fmt"
12 "internal/testenv"
13 "os"
14 "os/exec"
15 "path/filepath"
16 "regexp"
17 "runtime"
18 "strings"
19 "testing"
20 )
21
22 func TestOutput(t *testing.T) {
23 pkgdir := t.TempDir()
24 out, err := exec.Command(testenv.GoToolPath(t), "install", "-race", "-pkgdir="+pkgdir, "testing").CombinedOutput()
25 if err != nil {
26 t.Fatalf("go install -race: %v\n%s", err, out)
27 }
28
29 for _, test := range tests {
30 if test.goos != "" && test.goos != runtime.GOOS {
31 t.Logf("test %v runs only on %v, skipping: ", test.name, test.goos)
32 continue
33 }
34 dir := t.TempDir()
35 source := "main.go"
36 if test.run == "test" {
37 source = "main_test.go"
38 }
39 src := filepath.Join(dir, source)
40 f, err := os.Create(src)
41 if err != nil {
42 t.Fatalf("failed to create file: %v", err)
43 }
44 _, err = f.WriteString(test.source)
45 if err != nil {
46 f.Close()
47 t.Fatalf("failed to write: %v", err)
48 }
49 if err := f.Close(); err != nil {
50 t.Fatalf("failed to close file: %v", err)
51 }
52
53 cmd := exec.Command(testenv.GoToolPath(t), test.run, "-race", "-pkgdir="+pkgdir, src)
54
55 for _, env := range os.Environ() {
56 if strings.HasPrefix(env, "GODEBUG=") ||
57 strings.HasPrefix(env, "GOMAXPROCS=") ||
58 strings.HasPrefix(env, "GORACE=") {
59 continue
60 }
61 cmd.Env = append(cmd.Env, env)
62 }
63 cmd.Env = append(cmd.Env,
64 "GOMAXPROCS=1",
65 "GORACE="+test.gorace,
66 )
67 got, _ := cmd.CombinedOutput()
68 matched := false
69 for _, re := range test.re {
70 if regexp.MustCompile(re).MatchString(string(got)) {
71 matched = true
72 break
73 }
74 }
75 if !matched {
76 exp := fmt.Sprintf("expect:\n%v\n", test.re[0])
77 if len(test.re) > 1 {
78 exp = fmt.Sprintf("expected one of %d patterns:\n",
79 len(test.re))
80 for k, re := range test.re {
81 exp += fmt.Sprintf("pattern %d:\n%v\n", k, re)
82 }
83 }
84 t.Fatalf("failed test case %v, %sgot:\n%s",
85 test.name, exp, got)
86 }
87 }
88 }
89
90 var tests = []struct {
91 name string
92 run string
93 goos string
94 gorace string
95 source string
96 re []string
97 }{
98 {"simple", "run", "", "atexit_sleep_ms=0", `
99 package main
100 import "time"
101 var xptr *int
102 var donechan chan bool
103 func main() {
104 done := make(chan bool)
105 x := 0
106 startRacer(&x, done)
107 store(&x, 43)
108 <-done
109 }
110 func store(x *int, v int) {
111 *x = v
112 }
113 func startRacer(x *int, done chan bool) {
114 xptr = x
115 donechan = done
116 go racer()
117 }
118 func racer() {
119 time.Sleep(10*time.Millisecond)
120 store(xptr, 42)
121 donechan <- true
122 }
123 `, []string{`==================
124 WARNING: DATA RACE
125 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
126 main\.store\(\)
127 .+/main\.go:14 \+0x[0-9,a-f]+
128 main\.racer\(\)
129 .+/main\.go:23 \+0x[0-9,a-f]+
130
131 Previous write at 0x[0-9,a-f]+ by main goroutine:
132 main\.store\(\)
133 .+/main\.go:14 \+0x[0-9,a-f]+
134 main\.main\(\)
135 .+/main\.go:10 \+0x[0-9,a-f]+
136
137 Goroutine [0-9] \(running\) created at:
138 main\.startRacer\(\)
139 .+/main\.go:19 \+0x[0-9,a-f]+
140 main\.main\(\)
141 .+/main\.go:9 \+0x[0-9,a-f]+
142 ==================
143 Found 1 data race\(s\)
144 exit status 66
145 `}},
146
147 {"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
148 package main
149 func main() {
150 done := make(chan bool)
151 x := 0
152 go func() {
153 x = 42
154 done <- true
155 }()
156 x = 43
157 <-done
158 }
159 `, []string{`exit status 13`}},
160
161 {"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
162 package main
163 func main() {
164 done := make(chan bool)
165 x := 0
166 go func() {
167 x = 42
168 done <- true
169 }()
170 x = 43
171 <-done
172 }
173 `, []string{`
174 go:7 \+0x[0-9,a-f]+
175 `}},
176
177 {"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
178 package main
179 func main() {
180 done := make(chan bool)
181 x := 0
182 go func() {
183 x = 42
184 done <- true
185 }()
186 x = 43
187 <-done
188 }
189 `, []string{`
190 ==================
191 exit status 66
192 `}},
193
194 {"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
195 package main_test
196 import "testing"
197 func TestFail(t *testing.T) {
198 done := make(chan bool)
199 x := 0
200 _ = x
201 go func() {
202 x = 42
203 done <- true
204 }()
205 x = 43
206 <-done
207 t.Log(t.Failed())
208 }
209 `, []string{`
210 ==================
211 --- FAIL: TestFail \(0...s\)
212 .*main_test.go:14: true
213 .*testing.go:.*: race detected during execution of test
214 FAIL`}},
215
216 {"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
217 package main
218 func main() {
219 done := make(chan string)
220 data := make([]byte, 10)
221 go func() {
222 done <- string(data)
223 }()
224 data[0] = 1
225 <-done
226 }
227 `, []string{`
228 runtime\.slicebytetostring\(\)
229 .*/runtime/string\.go:.*
230 main\.main\.func1\(\)
231 .*/main.go:7`}},
232
233
234 {"midstack_inlining_traceback", "run", "linux", "atexit_sleep_ms=0", `
235 package main
236
237 var x int
238 var c chan int
239 func main() {
240 c = make(chan int)
241 go f()
242 x = 1
243 <-c
244 }
245
246 func f() {
247 g(c)
248 }
249
250 func g(c chan int) {
251 h(c)
252 }
253
254 func h(c chan int) {
255 c <- x
256 }
257 `, []string{`==================
258 WARNING: DATA RACE
259 Read at 0x[0-9,a-f]+ by goroutine [0-9]:
260 main\.h\(\)
261 .+/main\.go:22 \+0x[0-9,a-f]+
262 main\.g\(\)
263 .+/main\.go:18 \+0x[0-9,a-f]+
264 main\.f\(\)
265 .+/main\.go:14 \+0x[0-9,a-f]+
266
267 Previous write at 0x[0-9,a-f]+ by main goroutine:
268 main\.main\(\)
269 .+/main\.go:9 \+0x[0-9,a-f]+
270
271 Goroutine [0-9] \(running\) created at:
272 main\.main\(\)
273 .+/main\.go:8 \+0x[0-9,a-f]+
274 ==================
275 Found 1 data race\(s\)
276 exit status 66
277 `}},
278
279
280 {"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
281 package main
282
283 /*
284 #include <pthread.h>
285 typedef struct cb {
286 int foo;
287 } cb;
288 extern void goCallback();
289 static inline void *threadFunc(void *p) {
290 goCallback();
291 return 0;
292 }
293 static inline void startThread(cb* c) {
294 pthread_t th;
295 pthread_create(&th, 0, threadFunc, 0);
296 }
297 */
298 import "C"
299
300 var done chan bool
301 var racy int
302
303 //export goCallback
304 func goCallback() {
305 racy++
306 done <- true
307 }
308
309 func main() {
310 done = make(chan bool)
311 var c C.cb
312 C.startThread(&c)
313 racy++
314 <- done
315 }
316 `, []string{`==================
317 WARNING: DATA RACE
318 Read at 0x[0-9,a-f]+ by main goroutine:
319 main\.main\(\)
320 .*/main\.go:34 \+0x[0-9,a-f]+
321
322 Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
323 main\.goCallback\(\)
324 .*/main\.go:27 \+0x[0-9,a-f]+
325 _cgoexp_[0-9a-z]+_goCallback\(\)
326 .*_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
327 _cgoexp_[0-9a-z]+_goCallback\(\)
328 <autogenerated>:1 \+0x[0-9,a-f]+
329
330 Goroutine [0-9] \(running\) created at:
331 runtime\.newextram\(\)
332 .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
333 ==================`,
334 `==================
335 WARNING: DATA RACE
336 Read at 0x[0-9,a-f]+ by .*:
337 main\..*
338 .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
339
340 Previous write at 0x[0-9,a-f]+ by .*:
341 main\..*
342 .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
343
344 Goroutine [0-9] \(running\) created at:
345 runtime\.newextram\(\)
346 .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
347 ==================`}},
348 {"second_test_passes", "test", "", "atexit_sleep_ms=0", `
349 package main_test
350 import "testing"
351 func TestFail(t *testing.T) {
352 done := make(chan bool)
353 x := 0
354 _ = x
355 go func() {
356 x = 42
357 done <- true
358 }()
359 x = 43
360 <-done
361 }
362
363 func TestPass(t *testing.T) {
364 }
365 `, []string{`
366 ==================
367 --- FAIL: TestFail \(0...s\)
368 .*testing.go:.*: race detected during execution of test
369 FAIL`}},
370 {"mutex", "run", "", "atexit_sleep_ms=0", `
371 package main
372 import (
373 "sync"
374 "fmt"
375 )
376 func main() {
377 c := make(chan bool, 1)
378 threads := 1
379 iterations := 20000
380 data := 0
381 var wg sync.WaitGroup
382 for i := 0; i < threads; i++ {
383 wg.Add(1)
384 go func() {
385 defer wg.Done()
386 for i := 0; i < iterations; i++ {
387 c <- true
388 data += 1
389 <- c
390 }
391 }()
392 }
393 for i := 0; i < iterations; i++ {
394 c <- true
395 data += 1
396 <- c
397 }
398 wg.Wait()
399 if (data == iterations*(threads+1)) { fmt.Println("pass") }
400 }`, []string{`pass`}},
401
402 {"chanmm", "run", "", "atexit_sleep_ms=0", `
403 package main
404 import (
405 "sync"
406 "time"
407 )
408 func main() {
409 c := make(chan bool, 1)
410 var data uint64
411 var wg sync.WaitGroup
412 wg.Add(2)
413 c <- true
414 go func() {
415 defer wg.Done()
416 c <- true
417 }()
418 go func() {
419 defer wg.Done()
420 time.Sleep(time.Second)
421 <-c
422 data = 2
423 }()
424 data = 1
425 <-c
426 wg.Wait()
427 _ = data
428 }
429 `, []string{`==================
430 WARNING: DATA RACE
431 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
432 main\.main\.func2\(\)
433 .*/main\.go:21 \+0x[0-9,a-f]+
434
435 Previous write at 0x[0-9,a-f]+ by main goroutine:
436 main\.main\(\)
437 .*/main\.go:23 \+0x[0-9,a-f]+
438
439 Goroutine [0-9] \(running\) created at:
440 main\.main\(\)
441 .*/main.go:[0-9]+ \+0x[0-9,a-f]+
442 ==================`}},
443 }
444
View as plain text