github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/runtime/race/output_test.go (about) 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 // +build race 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 // GODEBUG spoils program output, GOMAXPROCS makes it flaky. 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", // see comment in race_test.go 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 // Test for https://golang.org/issue/33309 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 // Test for https://golang.org/issue/17190 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 // Test for https://github.com/golang/go/issues/37355 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 }