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