]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/race/output_test.go
0c636ff6c18caeb139f13acd8ae0a37bcfbc21c5
[gostls13.git] / src / runtime / race / output_test.go
1 // Copyright 2013 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:build race
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                 // GODEBUG spoils program output, GOMAXPROCS makes it flaky.
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", // see comment in race_test.go
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 .*main_test.go:14: true
212 .*testing.go:.*: race detected during execution of test
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         // Test for https://golang.org/issue/33309
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         // Test for https://golang.org/issue/17190
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         // Test for https://github.com/golang/go/issues/37355
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         // Test symbolizing wrappers. Both (*T).f and main.gowrap1 are wrappers.
443         // go.dev/issue/60245
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 }