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 t.Run(test.name, func(t *testing.T) {
30 if test.goos != "" && test.goos != runtime.GOOS {
31 t.Skipf("runs only on %v", test.goos)
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: %sgot:\n%s", exp, got)
84 }
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
124 `==================
125 WARNING: DATA RACE
126 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
127 main\.store\(\)
128 .+/main\.go:14 \+0x[0-9,a-f]+
129 main\.racer\(\)
130 .+/main\.go:23 \+0x[0-9,a-f]+
131
132 Previous write at 0x[0-9,a-f]+ by main goroutine:
133 main\.store\(\)
134 .+/main\.go:14 \+0x[0-9,a-f]+
135 main\.main\(\)
136 .+/main\.go:10 \+0x[0-9,a-f]+
137
138 Goroutine [0-9] \(running\) created at:
139 main\.startRacer\(\)
140 .+/main\.go:19 \+0x[0-9,a-f]+
141 main\.main\(\)
142 .+/main\.go:9 \+0x[0-9,a-f]+
143 ==================
144 Found 1 data race\(s\)
145 exit status 66
146 `,
147 `==================
148 WARNING: DATA RACE
149 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
150 main\.store\(\)
151 .+/main\.go:14 \+0x[0-9,a-f]+
152 main\.main\(\)
153 .+/main\.go:10 \+0x[0-9,a-f]+
154
155 Previous write at 0x[0-9,a-f]+ by main goroutine:
156 main\.store\(\)
157 .+/main\.go:14 \+0x[0-9,a-f]+
158 main\.racer\(\)
159 .+/main\.go:23 \+0x[0-9,a-f]+
160
161 Goroutine [0-9] \(running\) created at:
162 main\.startRacer\(\)
163 .+/main\.go:19 \+0x[0-9,a-f]+
164 main\.main\(\)
165 .+/main\.go:9 \+0x[0-9,a-f]+
166 ==================
167 Found 1 data race\(s\)
168 exit status 66
169 `}},
170
171 {"exitcode", "run", "", "atexit_sleep_ms=0 exitcode=13", `
172 package main
173 func main() {
174 done := make(chan bool)
175 x := 0; _ = x
176 go func() {
177 x = 42
178 done <- true
179 }()
180 x = 43
181 <-done
182 }
183 `, []string{`exit status 13`}},
184
185 {"strip_path_prefix", "run", "", "atexit_sleep_ms=0 strip_path_prefix=/main.", `
186 package main
187 func main() {
188 done := make(chan bool)
189 x := 0; _ = x
190 go func() {
191 x = 42
192 done <- true
193 }()
194 x = 43
195 <-done
196 }
197 `, []string{`
198 go:7 \+0x[0-9,a-f]+
199 `}},
200
201 {"halt_on_error", "run", "", "atexit_sleep_ms=0 halt_on_error=1", `
202 package main
203 func main() {
204 done := make(chan bool)
205 x := 0; _ = x
206 go func() {
207 x = 42
208 done <- true
209 }()
210 x = 43
211 <-done
212 }
213 `, []string{`
214 ==================
215 exit status 66
216 `}},
217
218 {"test_fails_on_race", "test", "", "atexit_sleep_ms=0", `
219 package main_test
220 import "testing"
221 func TestFail(t *testing.T) {
222 done := make(chan bool)
223 x := 0
224 _ = x
225 go func() {
226 x = 42
227 done <- true
228 }()
229 x = 43
230 <-done
231 t.Log(t.Failed())
232 }
233 `, []string{`
234 ==================
235 --- FAIL: TestFail \([0-9.]+s\)
236 .*testing.go:.*: race detected during execution of test
237 .*main_test.go:14: true
238 FAIL`}},
239
240 {"slicebytetostring_pc", "run", "", "atexit_sleep_ms=0", `
241 package main
242 func main() {
243 done := make(chan string)
244 data := make([]byte, 10)
245 go func() {
246 done <- string(data)
247 }()
248 data[0] = 1
249 <-done
250 }
251 `, []string{`
252 runtime\.slicebytetostring\(\)
253 .*/runtime/string\.go:.*
254 main\.main\.func1\(\)
255 .*/main.go:7`}},
256
257
258 {"midstack_inlining_traceback", "run", "linux", "atexit_sleep_ms=0", `
259 package main
260
261 var x int
262 var c chan int
263 func main() {
264 c = make(chan int)
265 go f()
266 x = 1
267 <-c
268 }
269
270 func f() {
271 g(c)
272 }
273
274 func g(c chan int) {
275 h(c)
276 }
277
278 func h(c chan int) {
279 c <- x
280 }
281 `, []string{
282
283 `==================
284 WARNING: DATA RACE
285 Read at 0x[0-9,a-f]+ by goroutine [0-9]:
286 main\.h\(\)
287 .+/main\.go:22 \+0x[0-9,a-f]+
288 main\.g\(\)
289 .+/main\.go:18 \+0x[0-9,a-f]+
290 main\.f\(\)
291 .+/main\.go:14 \+0x[0-9,a-f]+
292
293 Previous write at 0x[0-9,a-f]+ by main goroutine:
294 main\.main\(\)
295 .+/main\.go:9 \+0x[0-9,a-f]+
296
297 Goroutine [0-9] \(running\) created at:
298 main\.main\(\)
299 .+/main\.go:8 \+0x[0-9,a-f]+
300 ==================
301 Found 1 data race\(s\)
302 exit status 66
303 `,
304 `==================
305 WARNING: DATA RACE
306 Write at 0x[0-9,a-f]+ by main goroutine:
307 main\.main\(\)
308 .+/main\.go:9 \+0x[0-9,a-f]+
309
310 Previous read at 0x[0-9,a-f]+ by goroutine [0-9]:
311 main\.h\(\)
312 .+/main\.go:22 \+0x[0-9,a-f]+
313 main\.g\(\)
314 .+/main\.go:18 \+0x[0-9,a-f]+
315 main\.f\(\)
316 .+/main\.go:14 \+0x[0-9,a-f]+
317
318 Goroutine [0-9] \(running\) created at:
319 main\.main\(\)
320 .+/main\.go:8 \+0x[0-9,a-f]+
321 ==================
322 Found 1 data race\(s\)
323 exit status 66
324 `}},
325
326
327 {"external_cgo_thread", "run", "linux", "atexit_sleep_ms=0", `
328 package main
329
330 /*
331 #include <pthread.h>
332 typedef struct cb {
333 int foo;
334 } cb;
335 extern void goCallback();
336 static inline void *threadFunc(void *p) {
337 goCallback();
338 return 0;
339 }
340 static inline void startThread(cb* c) {
341 pthread_t th;
342 pthread_create(&th, 0, threadFunc, 0);
343 }
344 */
345 import "C"
346
347 var done chan bool
348 var racy int
349
350 //export goCallback
351 func goCallback() {
352 racy++
353 done <- true
354 }
355
356 func main() {
357 done = make(chan bool)
358 var c C.cb
359 C.startThread(&c)
360 racy++
361 <- done
362 }
363 `, []string{
364
365 `==================
366 WARNING: DATA RACE
367 Read at 0x[0-9,a-f]+ by main goroutine:
368 main\.main\(\)
369 .*/main\.go:34 \+0x[0-9,a-f]+
370
371 Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
372 main\.goCallback\(\)
373 .*/main\.go:27 \+0x[0-9,a-f]+
374 _cgoexp_[0-9a-z]+_goCallback\(\)
375 .*_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
376 _cgoexp_[0-9a-z]+_goCallback\(\)
377 <autogenerated>:1 \+0x[0-9,a-f]+
378
379 Goroutine [0-9] \(running\) created at:
380 runtime\.newextram\(\)
381 .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
382 ==================`,
383 `==================
384 WARNING: DATA RACE
385 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
386 main\.goCallback\(\)
387 .*/main\.go:27 \+0x[0-9,a-f]+
388 _cgoexp_[0-9a-z]+_goCallback\(\)
389 .*_cgo_gotypes\.go:[0-9]+ \+0x[0-9,a-f]+
390 _cgoexp_[0-9a-z]+_goCallback\(\)
391 <autogenerated>:1 \+0x[0-9,a-f]+
392
393 Previous read at 0x[0-9,a-f]+ by main goroutine:
394 main\.main\(\)
395 .*/main\.go:34 \+0x[0-9,a-f]+
396
397 Goroutine [0-9] \(running\) created at:
398 runtime\.newextram\(\)
399 .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
400 ==================`,
401 `==================
402 WARNING: DATA RACE
403 Read at 0x[0-9,a-f]+ by .*:
404 main\..*
405 .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
406
407 Previous write at 0x[0-9,a-f]+ by .*:
408 main\..*
409 .*/main\.go:[0-9]+ \+0x[0-9,a-f]+(?s).*
410
411 Goroutine [0-9] \(running\) created at:
412 runtime\.newextram\(\)
413 .*/runtime/proc.go:[0-9]+ \+0x[0-9,a-f]+
414 ==================`}},
415 {"second_test_passes", "test", "", "atexit_sleep_ms=0", `
416 package main_test
417 import "testing"
418 func TestFail(t *testing.T) {
419 done := make(chan bool)
420 x := 0
421 _ = x
422 go func() {
423 x = 42
424 done <- true
425 }()
426 x = 43
427 <-done
428 }
429
430 func TestPass(t *testing.T) {
431 }
432 `, []string{`
433 ==================
434 --- FAIL: TestFail \([0-9.]+s\)
435 .*testing.go:.*: race detected during execution of test
436 FAIL`}},
437 {"mutex", "run", "", "atexit_sleep_ms=0", `
438 package main
439 import (
440 "sync"
441 "fmt"
442 )
443 func main() {
444 c := make(chan bool, 1)
445 threads := 1
446 iterations := 20000
447 data := 0
448 var wg sync.WaitGroup
449 for i := 0; i < threads; i++ {
450 wg.Add(1)
451 go func() {
452 defer wg.Done()
453 for i := 0; i < iterations; i++ {
454 c <- true
455 data += 1
456 <- c
457 }
458 }()
459 }
460 for i := 0; i < iterations; i++ {
461 c <- true
462 data += 1
463 <- c
464 }
465 wg.Wait()
466 if (data == iterations*(threads+1)) { fmt.Println("pass") }
467 }`, []string{`pass`}},
468
469 {"chanmm", "run", "", "atexit_sleep_ms=0", `
470 package main
471 import (
472 "sync"
473 "time"
474 )
475 func main() {
476 c := make(chan bool, 1)
477 var data uint64
478 var wg sync.WaitGroup
479 wg.Add(2)
480 c <- true
481 go func() {
482 defer wg.Done()
483 c <- true
484 }()
485 go func() {
486 defer wg.Done()
487 time.Sleep(time.Second)
488 <-c
489 data = 2
490 }()
491 data = 1
492 <-c
493 wg.Wait()
494 _ = data
495 }
496 `, []string{
497
498 `==================
499 WARNING: DATA RACE
500 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
501 main\.main\.func2\(\)
502 .*/main\.go:21 \+0x[0-9,a-f]+
503
504 Previous write at 0x[0-9,a-f]+ by main goroutine:
505 main\.main\(\)
506 .*/main\.go:23 \+0x[0-9,a-f]+
507
508 Goroutine [0-9] \(running\) created at:
509 main\.main\(\)
510 .*/main.go:[0-9]+ \+0x[0-9,a-f]+
511 ==================`,
512 `==================
513 WARNING: DATA RACE
514 Write at 0x[0-9,a-f]+ by main goroutine:
515 main\.main\(\)
516 .*/main\.go:23 \+0x[0-9,a-f]+
517
518 Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
519 main\.main\.func2\(\)
520 .*/main\.go:21 \+0x[0-9,a-f]+
521
522 Goroutine [0-9] \(running\) created at:
523 main\.main\(\)
524 .*/main.go:[0-9]+ \+0x[0-9,a-f]+
525 ==================`}},
526
527
528 {"wrappersym", "run", "", "atexit_sleep_ms=0", `
529 package main
530 import "sync"
531 var wg sync.WaitGroup
532 var x int
533 func main() {
534 f := (*T).f
535 wg.Add(2)
536 go f(new(T))
537 f(new(T))
538 wg.Wait()
539 }
540 type T struct{}
541 func (t T) f() {
542 x = 42
543 wg.Done()
544 }
545 `, []string{
546
547 `==================
548 WARNING: DATA RACE
549 Write at 0x[0-9,a-f]+ by goroutine [0-9]:
550 main\.T\.f\(\)
551 .*/main.go:15 \+0x[0-9,a-f]+
552 main\.\(\*T\)\.f\(\)
553 <autogenerated>:1 \+0x[0-9,a-f]+
554 main\.main\.gowrap1\(\)
555 .*/main.go:9 \+0x[0-9,a-f]+
556
557 Previous write at 0x[0-9,a-f]+ by main goroutine:
558 main\.T\.f\(\)
559 .*/main.go:15 \+0x[0-9,a-f]+
560 main\.\(\*T\)\.f\(\)
561 <autogenerated>:1 \+0x[0-9,a-f]+
562 main\.main\(\)
563 .*/main.go:10 \+0x[0-9,a-f]+
564
565 `,
566 `==================
567 WARNING: DATA RACE
568 Write at 0x[0-9,a-f]+ by main goroutine:
569 main\.T\.f\(\)
570 .*/main.go:15 \+0x[0-9,a-f]+
571 main\.\(\*T\)\.f\(\)
572 <autogenerated>:1 \+0x[0-9,a-f]+
573 main\.main\(\)
574 .*/main.go:10 \+0x[0-9,a-f]+
575
576 Previous write at 0x[0-9,a-f]+ by goroutine [0-9]:
577 main\.T\.f\(\)
578 .*/main.go:15 \+0x[0-9,a-f]+
579 main\.\(\*T\)\.f\(\)
580 <autogenerated>:1 \+0x[0-9,a-f]+
581 main\.main\.gowrap1\(\)
582 .*/main.go:9 \+0x[0-9,a-f]+
583
584 `}},
585 {"non_inline_array_compare", "run", "", "atexit_sleep_ms=0", `
586 package main
587
588 import (
589 "math/rand/v2"
590 )
591
592 var x = [1024]byte{}
593
594 var ch = make(chan bool)
595
596 func main() {
597 started := make(chan struct{})
598 go func() {
599 close(started)
600 var y = [len(x)]byte{}
601 eq := x == y
602 ch <- eq
603 }()
604 <-started
605 x[rand.IntN(len(x))]++
606 println(<-ch)
607 }
608 `, []string{`==================
609 WARNING: DATA RACE
610 `}},
611 {"non_inline_struct_compare", "run", "", "atexit_sleep_ms=0", `
612 package main
613
614 import "math/rand/v2"
615
616 type S struct {
617 a [1024]byte
618 }
619
620 var x = S{a: [1024]byte{}}
621
622 var ch = make(chan bool)
623
624 func main() {
625 started := make(chan struct{})
626 go func() {
627 close(started)
628 var y = S{a: [len(x.a)]byte{}}
629 eq := x == y
630 ch <- eq
631 }()
632 <-started
633 x.a[rand.IntN(len(x.a))]++
634 println(<-ch)
635 }
636 `, []string{`==================
637 WARNING: DATA RACE
638 `}},
639 }
640
View as plain text