github.com/likebike/go--@v0.0.0-20190911215757-0bd925d16e96/go/src/runtime/crash_cgo_test.go (about) 1 // Copyright 2012 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 cgo 6 7 package runtime_test 8 9 import ( 10 "bytes" 11 "fmt" 12 "internal/testenv" 13 "os" 14 "os/exec" 15 "runtime" 16 "strconv" 17 "strings" 18 "testing" 19 "time" 20 ) 21 22 func TestCgoCrashHandler(t *testing.T) { 23 t.Parallel() 24 testCrashHandler(t, true) 25 } 26 27 func TestCgoSignalDeadlock(t *testing.T) { 28 // Don't call t.Parallel, since too much work going on at the 29 // same time can cause the testprogcgo code to overrun its 30 // timeouts (issue #18598). 31 32 if testing.Short() && runtime.GOOS == "windows" { 33 t.Skip("Skipping in short mode") // takes up to 64 seconds 34 } 35 got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock") 36 want := "OK\n" 37 if got != want { 38 t.Fatalf("expected %q, but got:\n%s", want, got) 39 } 40 } 41 42 func TestCgoTraceback(t *testing.T) { 43 t.Parallel() 44 got := runTestProg(t, "testprogcgo", "CgoTraceback") 45 want := "OK\n" 46 if got != want { 47 t.Fatalf("expected %q, but got:\n%s", want, got) 48 } 49 } 50 51 func TestCgoCallbackGC(t *testing.T) { 52 t.Parallel() 53 switch runtime.GOOS { 54 case "plan9", "windows": 55 t.Skipf("no pthreads on %s", runtime.GOOS) 56 } 57 if testing.Short() { 58 switch { 59 case runtime.GOOS == "dragonfly": 60 t.Skip("see golang.org/issue/11990") 61 case runtime.GOOS == "linux" && runtime.GOARCH == "arm": 62 t.Skip("too slow for arm builders") 63 case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le"): 64 t.Skip("too slow for mips64x builders") 65 } 66 } 67 got := runTestProg(t, "testprogcgo", "CgoCallbackGC") 68 want := "OK\n" 69 if got != want { 70 t.Fatalf("expected %q, but got:\n%s", want, got) 71 } 72 } 73 74 func TestCgoExternalThreadPanic(t *testing.T) { 75 t.Parallel() 76 if runtime.GOOS == "plan9" { 77 t.Skipf("no pthreads on %s", runtime.GOOS) 78 } 79 got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic") 80 want := "panic: BOOM" 81 if !strings.Contains(got, want) { 82 t.Fatalf("want failure containing %q. output:\n%s\n", want, got) 83 } 84 } 85 86 func TestCgoExternalThreadSIGPROF(t *testing.T) { 87 t.Parallel() 88 // issue 9456. 89 switch runtime.GOOS { 90 case "plan9", "windows": 91 t.Skipf("no pthreads on %s", runtime.GOOS) 92 case "darwin": 93 if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" { 94 // static constructor needs external linking, but we don't support 95 // external linking on OS X 10.6. 96 out, err := exec.Command("uname", "-r").Output() 97 if err != nil { 98 t.Fatalf("uname -r failed: %v", err) 99 } 100 // OS X 10.6 == Darwin 10.x 101 if strings.HasPrefix(string(out), "10.") { 102 t.Skipf("no external linking on OS X 10.6") 103 } 104 } 105 } 106 if runtime.GOARCH == "ppc64" { 107 // TODO(austin) External linking not implemented on 108 // ppc64 (issue #8912) 109 t.Skipf("no external linking on ppc64") 110 } 111 112 exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof") 113 if err != nil { 114 t.Fatal(err) 115 } 116 117 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() 118 if err != nil { 119 t.Fatalf("exit status: %v\n%s", err, got) 120 } 121 122 if want := "OK\n"; string(got) != want { 123 t.Fatalf("expected %q, but got:\n%s", want, got) 124 } 125 } 126 127 func TestCgoExternalThreadSignal(t *testing.T) { 128 t.Parallel() 129 // issue 10139 130 switch runtime.GOOS { 131 case "plan9", "windows": 132 t.Skipf("no pthreads on %s", runtime.GOOS) 133 } 134 135 exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof") 136 if err != nil { 137 t.Fatal(err) 138 } 139 140 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput() 141 if err != nil { 142 t.Fatalf("exit status: %v\n%s", err, got) 143 } 144 145 want := []byte("OK\n") 146 if !bytes.Equal(got, want) { 147 t.Fatalf("expected %q, but got:\n%s", want, got) 148 } 149 } 150 151 func TestCgoDLLImports(t *testing.T) { 152 // test issue 9356 153 if runtime.GOOS != "windows" { 154 t.Skip("skipping windows specific test") 155 } 156 got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain") 157 want := "OK\n" 158 if got != want { 159 t.Fatalf("expected %q, but got %v", want, got) 160 } 161 } 162 163 func TestCgoExecSignalMask(t *testing.T) { 164 t.Parallel() 165 // Test issue 13164. 166 switch runtime.GOOS { 167 case "windows", "plan9": 168 t.Skipf("skipping signal mask test on %s", runtime.GOOS) 169 } 170 got := runTestProg(t, "testprogcgo", "CgoExecSignalMask") 171 want := "OK\n" 172 if got != want { 173 t.Errorf("expected %q, got %v", want, got) 174 } 175 } 176 177 func TestEnsureDropM(t *testing.T) { 178 t.Parallel() 179 // Test for issue 13881. 180 switch runtime.GOOS { 181 case "windows", "plan9": 182 t.Skipf("skipping dropm test on %s", runtime.GOOS) 183 } 184 got := runTestProg(t, "testprogcgo", "EnsureDropM") 185 want := "OK\n" 186 if got != want { 187 t.Errorf("expected %q, got %v", want, got) 188 } 189 } 190 191 // Test for issue 14387. 192 // Test that the program that doesn't need any cgo pointer checking 193 // takes about the same amount of time with it as without it. 194 func TestCgoCheckBytes(t *testing.T) { 195 t.Parallel() 196 // Make sure we don't count the build time as part of the run time. 197 testenv.MustHaveGoBuild(t) 198 exe, err := buildTestProg(t, "testprogcgo") 199 if err != nil { 200 t.Fatal(err) 201 } 202 203 // Try it 10 times to avoid flakiness. 204 const tries = 10 205 var tot1, tot2 time.Duration 206 for i := 0; i < tries; i++ { 207 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) 208 cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 209 210 start := time.Now() 211 cmd.Run() 212 d1 := time.Since(start) 213 214 cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) 215 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 216 217 start = time.Now() 218 cmd.Run() 219 d2 := time.Since(start) 220 221 if d1*20 > d2 { 222 // The slow version (d2) was less than 20 times 223 // slower than the fast version (d1), so OK. 224 return 225 } 226 227 tot1 += d1 228 tot2 += d2 229 } 230 231 t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20) 232 } 233 234 func TestCgoPanicDeadlock(t *testing.T) { 235 t.Parallel() 236 // test issue 14432 237 got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock") 238 want := "panic: cgo error\n\n" 239 if !strings.HasPrefix(got, want) { 240 t.Fatalf("output does not start with %q:\n%s", want, got) 241 } 242 } 243 244 func TestCgoCCodeSIGPROF(t *testing.T) { 245 t.Parallel() 246 got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF") 247 want := "OK\n" 248 if got != want { 249 t.Errorf("expected %q got %v", want, got) 250 } 251 } 252 253 func TestCgoCrashTraceback(t *testing.T) { 254 t.Parallel() 255 if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { 256 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 257 } 258 got := runTestProg(t, "testprogcgo", "CrashTraceback") 259 for i := 1; i <= 3; i++ { 260 if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) { 261 t.Errorf("missing cgo symbolizer:%d", i) 262 } 263 } 264 } 265 266 func TestCgoTracebackContext(t *testing.T) { 267 t.Parallel() 268 got := runTestProg(t, "testprogcgo", "TracebackContext") 269 want := "OK\n" 270 if got != want { 271 t.Errorf("expected %q got %v", want, got) 272 } 273 } 274 275 func testCgoPprof(t *testing.T, buildArg, runArg string) { 276 t.Parallel() 277 if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") { 278 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 279 } 280 testenv.MustHaveGoRun(t) 281 282 exe, err := buildTestProg(t, "testprogcgo", buildArg) 283 if err != nil { 284 t.Fatal(err) 285 } 286 287 got, err := testenv.CleanCmdEnv(exec.Command(exe, runArg)).CombinedOutput() 288 if err != nil { 289 if testenv.Builder() == "linux-amd64-alpine" { 290 // See Issue 18243 and Issue 19938. 291 t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err) 292 } 293 t.Fatal(err) 294 } 295 fn := strings.TrimSpace(string(got)) 296 defer os.Remove(fn) 297 298 for try := 0; try < 2; try++ { 299 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1")) 300 // Check that pprof works both with and without explicit executable on command line. 301 if try == 0 { 302 cmd.Args = append(cmd.Args, exe, fn) 303 } else { 304 cmd.Args = append(cmd.Args, fn) 305 } 306 307 found := false 308 for i, e := range cmd.Env { 309 if strings.HasPrefix(e, "PPROF_TMPDIR=") { 310 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir() 311 found = true 312 break 313 } 314 } 315 if !found { 316 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir()) 317 } 318 319 top, err := cmd.CombinedOutput() 320 t.Logf("%s:\n%s", cmd.Args, top) 321 if err != nil { 322 t.Error(err) 323 } else if !bytes.Contains(top, []byte("cpuHog")) { 324 t.Error("missing cpuHog in pprof output") 325 } 326 } 327 } 328 329 func TestCgoPprof(t *testing.T) { 330 testCgoPprof(t, "", "CgoPprof") 331 } 332 333 func TestCgoPprofPIE(t *testing.T) { 334 testCgoPprof(t, "-buildmode=pie", "CgoPprof") 335 } 336 337 func TestCgoPprofThread(t *testing.T) { 338 testCgoPprof(t, "", "CgoPprofThread") 339 } 340 341 func TestCgoPprofThreadNoTraceback(t *testing.T) { 342 testCgoPprof(t, "", "CgoPprofThreadNoTraceback") 343 } 344 345 func TestRaceProf(t *testing.T) { 346 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 347 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 348 } 349 350 testenv.MustHaveGoRun(t) 351 352 // This test requires building various packages with -race, so 353 // it's somewhat slow. 354 if testing.Short() { 355 t.Skip("skipping test in -short mode") 356 } 357 358 exe, err := buildTestProg(t, "testprogcgo", "-race") 359 if err != nil { 360 t.Fatal(err) 361 } 362 363 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput() 364 if err != nil { 365 t.Fatal(err) 366 } 367 want := "OK\n" 368 if string(got) != want { 369 t.Errorf("expected %q got %s", want, got) 370 } 371 } 372 373 func TestRaceSignal(t *testing.T) { 374 t.Parallel() 375 if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" { 376 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 377 } 378 379 testenv.MustHaveGoRun(t) 380 381 // This test requires building various packages with -race, so 382 // it's somewhat slow. 383 if testing.Short() { 384 t.Skip("skipping test in -short mode") 385 } 386 387 exe, err := buildTestProg(t, "testprogcgo", "-race") 388 if err != nil { 389 t.Fatal(err) 390 } 391 392 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput() 393 if err != nil { 394 t.Logf("%s\n", got) 395 t.Fatal(err) 396 } 397 want := "OK\n" 398 if string(got) != want { 399 t.Errorf("expected %q got %s", want, got) 400 } 401 } 402 403 func TestCgoNumGoroutine(t *testing.T) { 404 switch runtime.GOOS { 405 case "windows", "plan9": 406 t.Skipf("skipping numgoroutine test on %s", runtime.GOOS) 407 } 408 t.Parallel() 409 got := runTestProg(t, "testprogcgo", "NumGoroutine") 410 want := "OK\n" 411 if got != want { 412 t.Errorf("expected %q got %v", want, got) 413 } 414 } 415 416 func TestCatchPanic(t *testing.T) { 417 t.Parallel() 418 switch runtime.GOOS { 419 case "plan9", "windows": 420 t.Skipf("no signals on %s", runtime.GOOS) 421 case "darwin": 422 if runtime.GOARCH == "amd64" { 423 t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT") 424 } 425 } 426 427 testenv.MustHaveGoRun(t) 428 429 exe, err := buildTestProg(t, "testprogcgo") 430 if err != nil { 431 t.Fatal(err) 432 } 433 434 for _, early := range []bool{true, false} { 435 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic")) 436 // Make sure a panic results in a crash. 437 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") 438 if early { 439 // Tell testprogcgo to install an early signal handler for SIGABRT 440 cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1") 441 } 442 if out, err := cmd.CombinedOutput(); err != nil { 443 t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out) 444 } 445 } 446 } 447 448 func TestCgoLockOSThreadExit(t *testing.T) { 449 switch runtime.GOOS { 450 case "plan9", "windows": 451 t.Skipf("no pthreads on %s", runtime.GOOS) 452 } 453 t.Parallel() 454 testLockOSThreadExit(t, "testprogcgo") 455 } 456 457 func TestWindowsStackMemoryCgo(t *testing.T) { 458 if runtime.GOOS != "windows" { 459 t.Skip("skipping windows specific test") 460 } 461 testenv.SkipFlaky(t, 22575) 462 o := runTestProg(t, "testprogcgo", "StackMemory") 463 stackUsage, err := strconv.Atoi(o) 464 if err != nil { 465 t.Fatalf("Failed to read stack usage: %v", err) 466 } 467 if expected, got := 100<<10, stackUsage; got > expected { 468 t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got) 469 } 470 } 471 472 func TestSigStackSwapping(t *testing.T) { 473 switch runtime.GOOS { 474 case "plan9", "windows": 475 t.Skipf("no sigaltstack on %s", runtime.GOOS) 476 } 477 t.Parallel() 478 got := runTestProg(t, "testprogcgo", "SigStack") 479 want := "OK\n" 480 if got != want { 481 t.Errorf("expected %q got %v", want, got) 482 } 483 } 484 485 func TestCgoTracebackSigpanic(t *testing.T) { 486 // Test unwinding over a sigpanic in C code without a C 487 // symbolizer. See issue #23576. 488 if runtime.GOOS == "windows" { 489 // On Windows if we get an exception in C code, we let 490 // the Windows exception handler unwind it, rather 491 // than injecting a sigpanic. 492 t.Skip("no sigpanic in C on windows") 493 } 494 t.Parallel() 495 got := runTestProg(t, "testprogcgo", "TracebackSigpanic") 496 want := "runtime.sigpanic" 497 if !strings.Contains(got, want) { 498 t.Fatalf("want failure containing %q. output:\n%s\n", want, got) 499 } 500 nowant := "unexpected return pc" 501 if strings.Contains(got, nowant) { 502 t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got) 503 } 504 }