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//go:build cgo 6 7package runtime_test 8 9import ( 10 "fmt" 11 "internal/goos" 12 "internal/platform" 13 "internal/testenv" 14 "os" 15 "os/exec" 16 "runtime" 17 "strconv" 18 "strings" 19 "testing" 20 "time" 21) 22 23func TestCgoCrashHandler(t *testing.T) { 24 t.Parallel() 25 testCrashHandler(t, true) 26} 27 28func TestCgoSignalDeadlock(t *testing.T) { 29 // Don't call t.Parallel, since too much work going on at the 30 // same time can cause the testprogcgo code to overrun its 31 // timeouts (issue #18598). 32 33 if testing.Short() && runtime.GOOS == "windows" { 34 t.Skip("Skipping in short mode") // takes up to 64 seconds 35 } 36 got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock") 37 want := "OK\n" 38 if got != want { 39 t.Fatalf("expected %q, but got:\n%s", want, got) 40 } 41} 42 43func TestCgoTraceback(t *testing.T) { 44 t.Parallel() 45 got := runTestProg(t, "testprogcgo", "CgoTraceback") 46 want := "OK\n" 47 if got != want { 48 t.Fatalf("expected %q, but got:\n%s", want, got) 49 } 50} 51 52func TestCgoCallbackGC(t *testing.T) { 53 t.Parallel() 54 switch runtime.GOOS { 55 case "plan9", "windows": 56 t.Skipf("no pthreads on %s", runtime.GOOS) 57 } 58 if testing.Short() { 59 switch { 60 case runtime.GOOS == "dragonfly": 61 t.Skip("see golang.org/issue/11990") 62 case runtime.GOOS == "linux" && runtime.GOARCH == "arm": 63 t.Skip("too slow for arm builders") 64 case runtime.GOOS == "linux" && (runtime.GOARCH == "mips64" || runtime.GOARCH == "mips64le"): 65 t.Skip("too slow for mips64x builders") 66 } 67 } 68 if testenv.Builder() == "darwin-amd64-10_14" { 69 // TODO(#23011): When the 10.14 builders are gone, remove this skip. 70 t.Skip("skipping due to platform bug on macOS 10.14; see https://golang.org/issue/43926") 71 } 72 got := runTestProg(t, "testprogcgo", "CgoCallbackGC") 73 want := "OK\n" 74 if got != want { 75 t.Fatalf("expected %q, but got:\n%s", want, got) 76 } 77} 78 79func TestCgoExternalThreadPanic(t *testing.T) { 80 t.Parallel() 81 if runtime.GOOS == "plan9" { 82 t.Skipf("no pthreads on %s", runtime.GOOS) 83 } 84 got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic") 85 want := "panic: BOOM" 86 if !strings.Contains(got, want) { 87 t.Fatalf("want failure containing %q. output:\n%s\n", want, got) 88 } 89} 90 91func TestCgoExternalThreadSIGPROF(t *testing.T) { 92 t.Parallel() 93 // issue 9456. 94 switch runtime.GOOS { 95 case "plan9", "windows": 96 t.Skipf("no pthreads on %s", runtime.GOOS) 97 } 98 99 got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF", "GO_START_SIGPROF_THREAD=1") 100 if want := "OK\n"; got != want { 101 t.Fatalf("expected %q, but got:\n%s", want, got) 102 } 103} 104 105func TestCgoExternalThreadSignal(t *testing.T) { 106 t.Parallel() 107 // issue 10139 108 switch runtime.GOOS { 109 case "plan9", "windows": 110 t.Skipf("no pthreads on %s", runtime.GOOS) 111 } 112 113 got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal") 114 if want := "OK\n"; got != want { 115 if runtime.GOOS == "ios" && strings.Contains(got, "C signal did not crash as expected") { 116 testenv.SkipFlaky(t, 59913) 117 } 118 t.Fatalf("expected %q, but got:\n%s", want, got) 119 } 120} 121 122func TestCgoDLLImports(t *testing.T) { 123 // test issue 9356 124 if runtime.GOOS != "windows" { 125 t.Skip("skipping windows specific test") 126 } 127 got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain") 128 want := "OK\n" 129 if got != want { 130 t.Fatalf("expected %q, but got %v", want, got) 131 } 132} 133 134func TestCgoExecSignalMask(t *testing.T) { 135 t.Parallel() 136 // Test issue 13164. 137 switch runtime.GOOS { 138 case "windows", "plan9": 139 t.Skipf("skipping signal mask test on %s", runtime.GOOS) 140 } 141 got := runTestProg(t, "testprogcgo", "CgoExecSignalMask", "GOTRACEBACK=system") 142 want := "OK\n" 143 if got != want { 144 t.Errorf("expected %q, got %v", want, got) 145 } 146} 147 148func TestEnsureDropM(t *testing.T) { 149 t.Parallel() 150 // Test for issue 13881. 151 switch runtime.GOOS { 152 case "windows", "plan9": 153 t.Skipf("skipping dropm test on %s", runtime.GOOS) 154 } 155 got := runTestProg(t, "testprogcgo", "EnsureDropM") 156 want := "OK\n" 157 if got != want { 158 t.Errorf("expected %q, got %v", want, got) 159 } 160} 161 162// Test for issue 14387. 163// Test that the program that doesn't need any cgo pointer checking 164// takes about the same amount of time with it as without it. 165func TestCgoCheckBytes(t *testing.T) { 166 t.Parallel() 167 // Make sure we don't count the build time as part of the run time. 168 testenv.MustHaveGoBuild(t) 169 exe, err := buildTestProg(t, "testprogcgo") 170 if err != nil { 171 t.Fatal(err) 172 } 173 174 // Try it 10 times to avoid flakiness. 175 const tries = 10 176 var tot1, tot2 time.Duration 177 for i := 0; i < tries; i++ { 178 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) 179 cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 180 181 start := time.Now() 182 cmd.Run() 183 d1 := time.Since(start) 184 185 cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes")) 186 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i)) 187 188 start = time.Now() 189 cmd.Run() 190 d2 := time.Since(start) 191 192 if d1*20 > d2 { 193 // The slow version (d2) was less than 20 times 194 // slower than the fast version (d1), so OK. 195 return 196 } 197 198 tot1 += d1 199 tot2 += d2 200 } 201 202 t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20) 203} 204 205func TestCgoPanicDeadlock(t *testing.T) { 206 t.Parallel() 207 // test issue 14432 208 got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock") 209 want := "panic: cgo error\n\n" 210 if !strings.HasPrefix(got, want) { 211 t.Fatalf("output does not start with %q:\n%s", want, got) 212 } 213} 214 215func TestCgoCCodeSIGPROF(t *testing.T) { 216 t.Parallel() 217 got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF") 218 want := "OK\n" 219 if got != want { 220 t.Errorf("expected %q got %v", want, got) 221 } 222} 223 224func TestCgoPprofCallback(t *testing.T) { 225 if testing.Short() { 226 t.Skip("skipping in short mode") // takes a full second 227 } 228 switch runtime.GOOS { 229 case "windows", "plan9": 230 t.Skipf("skipping cgo pprof callback test on %s", runtime.GOOS) 231 } 232 got := runTestProg(t, "testprogcgo", "CgoPprofCallback") 233 want := "OK\n" 234 if got != want { 235 t.Errorf("expected %q got %v", want, got) 236 } 237} 238 239func TestCgoCrashTraceback(t *testing.T) { 240 t.Parallel() 241 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform { 242 case "darwin/amd64": 243 case "linux/amd64": 244 case "linux/arm64": 245 case "linux/ppc64le": 246 default: 247 t.Skipf("not yet supported on %s", platform) 248 } 249 got := runTestProg(t, "testprogcgo", "CrashTraceback") 250 for i := 1; i <= 3; i++ { 251 if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) { 252 t.Errorf("missing cgo symbolizer:%d", i) 253 } 254 } 255} 256 257func TestCgoCrashTracebackGo(t *testing.T) { 258 t.Parallel() 259 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform { 260 case "darwin/amd64": 261 case "linux/amd64": 262 case "linux/arm64": 263 case "linux/ppc64le": 264 default: 265 t.Skipf("not yet supported on %s", platform) 266 } 267 got := runTestProg(t, "testprogcgo", "CrashTracebackGo") 268 for i := 1; i <= 3; i++ { 269 want := fmt.Sprintf("main.h%d", i) 270 if !strings.Contains(got, want) { 271 t.Errorf("missing %s", want) 272 } 273 } 274} 275 276func TestCgoTracebackContext(t *testing.T) { 277 t.Parallel() 278 got := runTestProg(t, "testprogcgo", "TracebackContext") 279 want := "OK\n" 280 if got != want { 281 t.Errorf("expected %q got %v", want, got) 282 } 283} 284 285func TestCgoTracebackContextPreemption(t *testing.T) { 286 t.Parallel() 287 got := runTestProg(t, "testprogcgo", "TracebackContextPreemption") 288 want := "OK\n" 289 if got != want { 290 t.Errorf("expected %q got %v", want, got) 291 } 292} 293 294func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) { 295 t.Parallel() 296 if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "arm64") { 297 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH) 298 } 299 testenv.MustHaveGoRun(t) 300 301 exe, err := buildTestProg(t, "testprogcgo", buildArg) 302 if err != nil { 303 t.Fatal(err) 304 } 305 306 cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg)) 307 got, err := cmd.CombinedOutput() 308 if err != nil { 309 if testenv.Builder() == "linux-amd64-alpine" { 310 // See Issue 18243 and Issue 19938. 311 t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err) 312 } 313 t.Fatalf("%s\n\n%v", got, err) 314 } 315 fn := strings.TrimSpace(string(got)) 316 defer os.Remove(fn) 317 318 for try := 0; try < 2; try++ { 319 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-tagignore=ignore", "-traces")) 320 // Check that pprof works both with and without explicit executable on command line. 321 if try == 0 { 322 cmd.Args = append(cmd.Args, exe, fn) 323 } else { 324 cmd.Args = append(cmd.Args, fn) 325 } 326 327 found := false 328 for i, e := range cmd.Env { 329 if strings.HasPrefix(e, "PPROF_TMPDIR=") { 330 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir() 331 found = true 332 break 333 } 334 } 335 if !found { 336 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir()) 337 } 338 339 out, err := cmd.CombinedOutput() 340 t.Logf("%s:\n%s", cmd.Args, out) 341 if err != nil { 342 t.Error(err) 343 continue 344 } 345 346 trace := findTrace(string(out), top) 347 if len(trace) == 0 { 348 t.Errorf("%s traceback missing.", top) 349 continue 350 } 351 if trace[len(trace)-1] != bottom { 352 t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom) 353 } 354 } 355} 356 357func TestCgoPprof(t *testing.T) { 358 testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main") 359} 360 361func TestCgoPprofPIE(t *testing.T) { 362 testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main") 363} 364 365func TestCgoPprofThread(t *testing.T) { 366 testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2") 367} 368 369func TestCgoPprofThreadNoTraceback(t *testing.T) { 370 testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode") 371} 372 373func TestRaceProf(t *testing.T) { 374 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) { 375 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH) 376 } 377 if runtime.GOOS == "windows" { 378 t.Skipf("skipping: test requires pthread support") 379 // TODO: Can this test be rewritten to use the C11 thread API instead? 380 } 381 382 testenv.MustHaveGoRun(t) 383 384 // This test requires building various packages with -race, so 385 // it's somewhat slow. 386 if testing.Short() { 387 t.Skip("skipping test in -short mode") 388 } 389 390 exe, err := buildTestProg(t, "testprogcgo", "-race") 391 if err != nil { 392 t.Fatal(err) 393 } 394 395 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput() 396 if err != nil { 397 t.Fatal(err) 398 } 399 want := "OK\n" 400 if string(got) != want { 401 t.Errorf("expected %q got %s", want, got) 402 } 403} 404 405func TestRaceSignal(t *testing.T) { 406 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) { 407 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH) 408 } 409 if runtime.GOOS == "windows" { 410 t.Skipf("skipping: test requires pthread support") 411 // TODO: Can this test be rewritten to use the C11 thread API instead? 412 } 413 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" { 414 testenv.SkipFlaky(t, 60316) 415 } 416 417 t.Parallel() 418 419 testenv.MustHaveGoRun(t) 420 421 // This test requires building various packages with -race, so 422 // it's somewhat slow. 423 if testing.Short() { 424 t.Skip("skipping test in -short mode") 425 } 426 427 exe, err := buildTestProg(t, "testprogcgo", "-race") 428 if err != nil { 429 t.Fatal(err) 430 } 431 432 got, err := testenv.CleanCmdEnv(testenv.Command(t, exe, "CgoRaceSignal")).CombinedOutput() 433 if err != nil { 434 t.Logf("%s\n", got) 435 t.Fatal(err) 436 } 437 want := "OK\n" 438 if string(got) != want { 439 t.Errorf("expected %q got %s", want, got) 440 } 441} 442 443func TestCgoNumGoroutine(t *testing.T) { 444 switch runtime.GOOS { 445 case "windows", "plan9": 446 t.Skipf("skipping numgoroutine test on %s", runtime.GOOS) 447 } 448 t.Parallel() 449 got := runTestProg(t, "testprogcgo", "NumGoroutine") 450 want := "OK\n" 451 if got != want { 452 t.Errorf("expected %q got %v", want, got) 453 } 454} 455 456func TestCatchPanic(t *testing.T) { 457 t.Parallel() 458 switch runtime.GOOS { 459 case "plan9", "windows": 460 t.Skipf("no signals on %s", runtime.GOOS) 461 case "darwin": 462 if runtime.GOARCH == "amd64" { 463 t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT") 464 } 465 } 466 467 testenv.MustHaveGoRun(t) 468 469 exe, err := buildTestProg(t, "testprogcgo") 470 if err != nil { 471 t.Fatal(err) 472 } 473 474 for _, early := range []bool{true, false} { 475 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic")) 476 // Make sure a panic results in a crash. 477 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash") 478 if early { 479 // Tell testprogcgo to install an early signal handler for SIGABRT 480 cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1") 481 } 482 if out, err := cmd.CombinedOutput(); err != nil { 483 t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out) 484 } 485 } 486} 487 488func TestCgoLockOSThreadExit(t *testing.T) { 489 switch runtime.GOOS { 490 case "plan9", "windows": 491 t.Skipf("no pthreads on %s", runtime.GOOS) 492 } 493 t.Parallel() 494 testLockOSThreadExit(t, "testprogcgo") 495} 496 497func TestWindowsStackMemoryCgo(t *testing.T) { 498 if runtime.GOOS != "windows" { 499 t.Skip("skipping windows specific test") 500 } 501 testenv.SkipFlaky(t, 22575) 502 o := runTestProg(t, "testprogcgo", "StackMemory") 503 stackUsage, err := strconv.Atoi(o) 504 if err != nil { 505 t.Fatalf("Failed to read stack usage: %v", err) 506 } 507 if expected, got := 100<<10, stackUsage; got > expected { 508 t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got) 509 } 510} 511 512func TestSigStackSwapping(t *testing.T) { 513 switch runtime.GOOS { 514 case "plan9", "windows": 515 t.Skipf("no sigaltstack on %s", runtime.GOOS) 516 } 517 t.Parallel() 518 got := runTestProg(t, "testprogcgo", "SigStack") 519 want := "OK\n" 520 if got != want { 521 t.Errorf("expected %q got %v", want, got) 522 } 523} 524 525func TestCgoTracebackSigpanic(t *testing.T) { 526 // Test unwinding over a sigpanic in C code without a C 527 // symbolizer. See issue #23576. 528 if runtime.GOOS == "windows" { 529 // On Windows if we get an exception in C code, we let 530 // the Windows exception handler unwind it, rather 531 // than injecting a sigpanic. 532 t.Skip("no sigpanic in C on windows") 533 } 534 if runtime.GOOS == "ios" { 535 testenv.SkipFlaky(t, 59912) 536 } 537 t.Parallel() 538 got := runTestProg(t, "testprogcgo", "TracebackSigpanic") 539 t.Log(got) 540 // We should see the function that calls the C function. 541 want := "main.TracebackSigpanic" 542 if !strings.Contains(got, want) { 543 if runtime.GOOS == "android" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") { 544 testenv.SkipFlaky(t, 58794) 545 } 546 t.Errorf("did not see %q in output", want) 547 } 548 // We shouldn't inject a sigpanic call. (see issue 57698) 549 nowant := "runtime.sigpanic" 550 if strings.Contains(got, nowant) { 551 t.Errorf("unexpectedly saw %q in output", nowant) 552 } 553 // No runtime errors like "runtime: unexpected return pc". 554 nowant = "runtime: " 555 if strings.Contains(got, nowant) { 556 t.Errorf("unexpectedly saw %q in output", nowant) 557 } 558} 559 560func TestCgoPanicCallback(t *testing.T) { 561 t.Parallel() 562 got := runTestProg(t, "testprogcgo", "PanicCallback") 563 t.Log(got) 564 want := "panic: runtime error: invalid memory address or nil pointer dereference" 565 if !strings.Contains(got, want) { 566 t.Errorf("did not see %q in output", want) 567 } 568 want = "panic_callback" 569 if !strings.Contains(got, want) { 570 t.Errorf("did not see %q in output", want) 571 } 572 want = "PanicCallback" 573 if !strings.Contains(got, want) { 574 t.Errorf("did not see %q in output", want) 575 } 576 // No runtime errors like "runtime: unexpected return pc". 577 nowant := "runtime: " 578 if strings.Contains(got, nowant) { 579 t.Errorf("did not see %q in output", want) 580 } 581} 582 583// Test that C code called via cgo can use large Windows thread stacks 584// and call back in to Go without crashing. See issue #20975. 585// 586// See also TestBigStackCallbackSyscall. 587func TestBigStackCallbackCgo(t *testing.T) { 588 if runtime.GOOS != "windows" { 589 t.Skip("skipping windows specific test") 590 } 591 t.Parallel() 592 got := runTestProg(t, "testprogcgo", "BigStack") 593 want := "OK\n" 594 if got != want { 595 t.Errorf("expected %q got %v", want, got) 596 } 597} 598 599func nextTrace(lines []string) ([]string, []string) { 600 var trace []string 601 for n, line := range lines { 602 if strings.HasPrefix(line, "---") { 603 return trace, lines[n+1:] 604 } 605 fields := strings.Fields(strings.TrimSpace(line)) 606 if len(fields) == 0 { 607 continue 608 } 609 // Last field contains the function name. 610 trace = append(trace, fields[len(fields)-1]) 611 } 612 return nil, nil 613} 614 615func findTrace(text, top string) []string { 616 lines := strings.Split(text, "\n") 617 _, lines = nextTrace(lines) // Skip the header. 618 for len(lines) > 0 { 619 var t []string 620 t, lines = nextTrace(lines) 621 if len(t) == 0 { 622 continue 623 } 624 if t[0] == top { 625 return t 626 } 627 } 628 return nil 629} 630 631func TestSegv(t *testing.T) { 632 switch runtime.GOOS { 633 case "plan9", "windows": 634 t.Skipf("no signals on %s", runtime.GOOS) 635 } 636 637 for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} { 638 test := test 639 640 // The tgkill variants only run on Linux. 641 if runtime.GOOS != "linux" && strings.HasPrefix(test, "Tgkill") { 642 continue 643 } 644 645 t.Run(test, func(t *testing.T) { 646 if test == "SegvInCgo" && runtime.GOOS == "ios" { 647 testenv.SkipFlaky(t, 59947) // Don't even try, in case it times out. 648 } 649 650 t.Parallel() 651 prog := "testprog" 652 if strings.HasSuffix(test, "InCgo") { 653 prog = "testprogcgo" 654 } 655 got := runTestProg(t, prog, test) 656 t.Log(got) 657 want := "SIGSEGV" 658 if !strings.Contains(got, want) { 659 if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" && strings.Contains(got, "fatal: morestack on g0") { 660 testenv.SkipFlaky(t, 39457) 661 } 662 t.Errorf("did not see %q in output", want) 663 } 664 665 // No runtime errors like "runtime: unknown pc". 666 switch runtime.GOOS { 667 case "darwin", "ios", "illumos", "solaris": 668 // Runtime sometimes throws when generating the traceback. 669 testenv.SkipFlaky(t, 49182) 670 case "linux": 671 if runtime.GOARCH == "386" { 672 // Runtime throws when generating a traceback from 673 // a VDSO call via asmcgocall. 674 testenv.SkipFlaky(t, 50504) 675 } 676 } 677 if test == "SegvInCgo" && strings.Contains(got, "unknown pc") { 678 testenv.SkipFlaky(t, 50979) 679 } 680 681 for _, nowant := range []string{"fatal error: ", "runtime: "} { 682 if strings.Contains(got, nowant) { 683 if runtime.GOOS == "darwin" && strings.Contains(got, "0xb01dfacedebac1e") { 684 // See the comment in signal_darwin_amd64.go. 685 t.Skip("skipping due to Darwin handling of malformed addresses") 686 } 687 t.Errorf("unexpectedly saw %q in output", nowant) 688 } 689 } 690 }) 691 } 692} 693 694func TestAbortInCgo(t *testing.T) { 695 switch runtime.GOOS { 696 case "plan9", "windows": 697 // N.B. On Windows, C abort() causes the program to exit 698 // without going through the runtime at all. 699 t.Skipf("no signals on %s", runtime.GOOS) 700 } 701 702 t.Parallel() 703 got := runTestProg(t, "testprogcgo", "Abort") 704 t.Log(got) 705 want := "SIGABRT" 706 if !strings.Contains(got, want) { 707 t.Errorf("did not see %q in output", want) 708 } 709 // No runtime errors like "runtime: unknown pc". 710 nowant := "runtime: " 711 if strings.Contains(got, nowant) { 712 t.Errorf("did not see %q in output", want) 713 } 714} 715 716// TestEINTR tests that we handle EINTR correctly. 717// See issue #20400 and friends. 718func TestEINTR(t *testing.T) { 719 switch runtime.GOOS { 720 case "plan9", "windows": 721 t.Skipf("no EINTR on %s", runtime.GOOS) 722 case "linux": 723 if runtime.GOARCH == "386" { 724 // On linux-386 the Go signal handler sets 725 // a restorer function that is not preserved 726 // by the C sigaction call in the test, 727 // causing the signal handler to crash when 728 // returning the normal code. The test is not 729 // architecture-specific, so just skip on 386 730 // rather than doing a complicated workaround. 731 t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer") 732 } 733 } 734 735 t.Parallel() 736 output := runTestProg(t, "testprogcgo", "EINTR") 737 want := "OK\n" 738 if output != want { 739 t.Fatalf("want %s, got %s\n", want, output) 740 } 741} 742 743// Issue #42207. 744func TestNeedmDeadlock(t *testing.T) { 745 switch runtime.GOOS { 746 case "plan9", "windows": 747 t.Skipf("no signals on %s", runtime.GOOS) 748 } 749 output := runTestProg(t, "testprogcgo", "NeedmDeadlock") 750 want := "OK\n" 751 if output != want { 752 t.Fatalf("want %s, got %s\n", want, output) 753 } 754} 755 756func TestCgoNoCallback(t *testing.T) { 757 t.Skip("TODO(#56378): enable in Go 1.23") 758 got := runTestProg(t, "testprogcgo", "CgoNoCallback") 759 want := "function marked with #cgo nocallback called back into Go" 760 if !strings.Contains(got, want) { 761 t.Fatalf("did not see %q in output:\n%s", want, got) 762 } 763} 764 765func TestCgoNoEscape(t *testing.T) { 766 t.Skip("TODO(#56378): enable in Go 1.23") 767 got := runTestProg(t, "testprogcgo", "CgoNoEscape") 768 want := "OK\n" 769 if got != want { 770 t.Fatalf("want %s, got %s\n", want, got) 771 } 772} 773 774func TestCgoTracebackGoroutineProfile(t *testing.T) { 775 output := runTestProg(t, "testprogcgo", "GoroutineProfile") 776 want := "OK\n" 777 if output != want { 778 t.Fatalf("want %s, got %s\n", want, output) 779 } 780} 781 782func TestCgoSigfwd(t *testing.T) { 783 t.Parallel() 784 if !goos.IsUnix { 785 t.Skipf("no signals on %s", runtime.GOOS) 786 } 787 788 got := runTestProg(t, "testprogcgo", "CgoSigfwd", "GO_TEST_CGOSIGFWD=1") 789 if want := "OK\n"; got != want { 790 t.Fatalf("expected %q, but got:\n%s", want, got) 791 } 792} 793 794func TestDestructorCallback(t *testing.T) { 795 t.Parallel() 796 got := runTestProg(t, "testprogcgo", "DestructorCallback") 797 if want := "OK\n"; got != want { 798 t.Errorf("expected %q, but got:\n%s", want, got) 799 } 800} 801 802func TestDestructorCallbackRace(t *testing.T) { 803 // This test requires building with -race, 804 // so it's somewhat slow. 805 if testing.Short() { 806 t.Skip("skipping test in -short mode") 807 } 808 809 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) { 810 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH) 811 } 812 813 t.Parallel() 814 815 exe, err := buildTestProg(t, "testprogcgo", "-race") 816 if err != nil { 817 t.Fatal(err) 818 } 819 820 got, err := testenv.CleanCmdEnv(exec.Command(exe, "DestructorCallback")).CombinedOutput() 821 if err != nil { 822 t.Fatal(err) 823 } 824 825 if want := "OK\n"; string(got) != want { 826 t.Errorf("expected %q, but got:\n%s", want, got) 827 } 828} 829 830func TestEnsureBindM(t *testing.T) { 831 t.Parallel() 832 switch runtime.GOOS { 833 case "windows", "plan9": 834 t.Skipf("skipping bindm test on %s", runtime.GOOS) 835 } 836 got := runTestProg(t, "testprogcgo", "EnsureBindM") 837 want := "OK\n" 838 if got != want { 839 t.Errorf("expected %q, got %v", want, got) 840 } 841} 842 843func TestStackSwitchCallback(t *testing.T) { 844 t.Parallel() 845 switch runtime.GOOS { 846 case "windows", "plan9", "android", "ios", "openbsd": // no getcontext 847 t.Skipf("skipping test on %s", runtime.GOOS) 848 } 849 got := runTestProg(t, "testprogcgo", "StackSwitchCallback") 850 skip := "SKIP\n" 851 if got == skip { 852 t.Skip("skipping on musl/bionic libc") 853 } 854 want := "OK\n" 855 if got != want { 856 t.Errorf("expected %q, got %v", want, got) 857 } 858} 859