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