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.
23 func TestCgoCrashHandler(t *testing.T) {
25 testCrashHandler(t, true)
28 func 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).
33 if testing.Short() && runtime.GOOS == "windows" {
34 t.Skip("Skipping in short mode") // takes up to 64 seconds
36 got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock")
39 t.Fatalf("expected %q, but got:\n%s", want, got)
43 func TestCgoTraceback(t *testing.T) {
45 got := runTestProg(t, "testprogcgo", "CgoTraceback")
48 t.Fatalf("expected %q, but got:\n%s", want, got)
52 func TestCgoCallbackGC(t *testing.T) {
55 case "plan9", "windows":
56 t.Skipf("no pthreads on %s", runtime.GOOS)
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")
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")
72 got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
75 t.Fatalf("expected %q, but got:\n%s", want, got)
79 func TestCgoExternalThreadPanic(t *testing.T) {
81 if runtime.GOOS == "plan9" {
82 t.Skipf("no pthreads on %s", runtime.GOOS)
84 got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
86 if !strings.Contains(got, want) {
87 t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
91 func TestCgoExternalThreadSIGPROF(t *testing.T) {
95 case "plan9", "windows":
96 t.Skipf("no pthreads on %s", runtime.GOOS)
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)
105 func TestCgoExternalThreadSignal(t *testing.T) {
108 switch runtime.GOOS {
109 case "plan9", "windows":
110 t.Skipf("no pthreads on %s", runtime.GOOS)
113 got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
114 if want := "OK\n"; got != want {
115 t.Fatalf("expected %q, but got:\n%s", want, got)
119 func TestCgoDLLImports(t *testing.T) {
121 if runtime.GOOS != "windows" {
122 t.Skip("skipping windows specific test")
124 got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
127 t.Fatalf("expected %q, but got %v", want, got)
131 func TestCgoExecSignalMask(t *testing.T) {
134 switch runtime.GOOS {
135 case "windows", "plan9":
136 t.Skipf("skipping signal mask test on %s", runtime.GOOS)
138 got := runTestProg(t, "testprogcgo", "CgoExecSignalMask", "GOTRACEBACK=system")
141 t.Errorf("expected %q, got %v", want, got)
145 func TestEnsureDropM(t *testing.T) {
147 // Test for issue 13881.
148 switch runtime.GOOS {
149 case "windows", "plan9":
150 t.Skipf("skipping dropm test on %s", runtime.GOOS)
152 got := runTestProg(t, "testprogcgo", "EnsureDropM")
155 t.Errorf("expected %q, got %v", want, got)
159 // Test for issue 14387.
160 // Test that the program that doesn't need any cgo pointer checking
161 // takes about the same amount of time with it as without it.
162 func TestCgoCheckBytes(t *testing.T) {
164 // Make sure we don't count the build time as part of the run time.
165 testenv.MustHaveGoBuild(t)
166 exe, err := buildTestProg(t, "testprogcgo")
171 // Try it 10 times to avoid flakiness.
173 var tot1, tot2 time.Duration
174 for i := 0; i < tries; i++ {
175 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
176 cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
180 d1 := time.Since(start)
182 cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
183 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
187 d2 := time.Since(start)
190 // The slow version (d2) was less than 20 times
191 // slower than the fast version (d1), so OK.
199 t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
202 func TestCgoPanicDeadlock(t *testing.T) {
205 got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
206 want := "panic: cgo error\n\n"
207 if !strings.HasPrefix(got, want) {
208 t.Fatalf("output does not start with %q:\n%s", want, got)
212 func TestCgoCCodeSIGPROF(t *testing.T) {
214 got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
217 t.Errorf("expected %q got %v", want, got)
221 func TestCgoPprofCallback(t *testing.T) {
223 t.Skip("skipping in short mode") // takes a full second
225 switch runtime.GOOS {
226 case "windows", "plan9":
227 t.Skipf("skipping cgo pprof callback test on %s", runtime.GOOS)
229 got := runTestProg(t, "testprogcgo", "CgoPprofCallback")
232 t.Errorf("expected %q got %v", want, got)
236 func TestCgoCrashTraceback(t *testing.T) {
238 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
242 case "linux/ppc64le":
244 t.Skipf("not yet supported on %s", platform)
246 got := runTestProg(t, "testprogcgo", "CrashTraceback")
247 for i := 1; i <= 3; i++ {
248 if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
249 t.Errorf("missing cgo symbolizer:%d", i)
254 func TestCgoCrashTracebackGo(t *testing.T) {
256 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
260 case "linux/ppc64le":
262 t.Skipf("not yet supported on %s", platform)
264 got := runTestProg(t, "testprogcgo", "CrashTracebackGo")
265 for i := 1; i <= 3; i++ {
266 want := fmt.Sprintf("main.h%d", i)
267 if !strings.Contains(got, want) {
268 t.Errorf("missing %s", want)
273 func TestCgoTracebackContext(t *testing.T) {
275 got := runTestProg(t, "testprogcgo", "TracebackContext")
278 t.Errorf("expected %q got %v", want, got)
282 func TestCgoTracebackContextPreemption(t *testing.T) {
284 got := runTestProg(t, "testprogcgo", "TracebackContextPreemption")
287 t.Errorf("expected %q got %v", want, got)
291 func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
293 if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "arm64") {
294 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
296 testenv.MustHaveGoRun(t)
298 exe, err := buildTestProg(t, "testprogcgo", buildArg)
303 cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg))
304 got, err := cmd.CombinedOutput()
306 if testenv.Builder() == "linux-amd64-alpine" {
307 // See Issue 18243 and Issue 19938.
308 t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
310 t.Fatalf("%s\n\n%v", got, err)
312 fn := strings.TrimSpace(string(got))
315 for try := 0; try < 2; try++ {
316 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-tagignore=ignore", "-traces"))
317 // Check that pprof works both with and without explicit executable on command line.
319 cmd.Args = append(cmd.Args, exe, fn)
321 cmd.Args = append(cmd.Args, fn)
325 for i, e := range cmd.Env {
326 if strings.HasPrefix(e, "PPROF_TMPDIR=") {
327 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
333 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
336 out, err := cmd.CombinedOutput()
337 t.Logf("%s:\n%s", cmd.Args, out)
343 trace := findTrace(string(out), top)
345 t.Errorf("%s traceback missing.", top)
348 if trace[len(trace)-1] != bottom {
349 t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
354 func TestCgoPprof(t *testing.T) {
355 testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
358 func TestCgoPprofPIE(t *testing.T) {
359 testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
362 func TestCgoPprofThread(t *testing.T) {
363 testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
366 func TestCgoPprofThreadNoTraceback(t *testing.T) {
367 testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
370 func TestRaceProf(t *testing.T) {
371 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
372 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
374 if runtime.GOOS == "windows" {
375 t.Skipf("skipping: test requires pthread support")
376 // TODO: Can this test be rewritten to use the C11 thread API instead?
379 testenv.MustHaveGoRun(t)
381 // This test requires building various packages with -race, so
382 // it's somewhat slow.
384 t.Skip("skipping test in -short mode")
387 exe, err := buildTestProg(t, "testprogcgo", "-race")
392 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
397 if string(got) != want {
398 t.Errorf("expected %q got %s", want, got)
402 func TestRaceSignal(t *testing.T) {
403 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
404 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
406 if runtime.GOOS == "windows" {
407 t.Skipf("skipping: test requires pthread support")
408 // TODO: Can this test be rewritten to use the C11 thread API instead?
410 if runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
411 testenv.SkipFlaky(t, 59807)
416 testenv.MustHaveGoRun(t)
418 // This test requires building various packages with -race, so
419 // it's somewhat slow.
421 t.Skip("skipping test in -short mode")
424 exe, err := buildTestProg(t, "testprogcgo", "-race")
429 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
435 if string(got) != want {
436 t.Errorf("expected %q got %s", want, got)
440 func TestCgoNumGoroutine(t *testing.T) {
441 switch runtime.GOOS {
442 case "windows", "plan9":
443 t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
446 got := runTestProg(t, "testprogcgo", "NumGoroutine")
449 t.Errorf("expected %q got %v", want, got)
453 func TestCatchPanic(t *testing.T) {
455 switch runtime.GOOS {
456 case "plan9", "windows":
457 t.Skipf("no signals on %s", runtime.GOOS)
459 if runtime.GOARCH == "amd64" {
460 t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
464 testenv.MustHaveGoRun(t)
466 exe, err := buildTestProg(t, "testprogcgo")
471 for _, early := range []bool{true, false} {
472 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
473 // Make sure a panic results in a crash.
474 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
476 // Tell testprogcgo to install an early signal handler for SIGABRT
477 cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
479 if out, err := cmd.CombinedOutput(); err != nil {
480 t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
485 func TestCgoLockOSThreadExit(t *testing.T) {
486 switch runtime.GOOS {
487 case "plan9", "windows":
488 t.Skipf("no pthreads on %s", runtime.GOOS)
491 testLockOSThreadExit(t, "testprogcgo")
494 func TestWindowsStackMemoryCgo(t *testing.T) {
495 if runtime.GOOS != "windows" {
496 t.Skip("skipping windows specific test")
498 testenv.SkipFlaky(t, 22575)
499 o := runTestProg(t, "testprogcgo", "StackMemory")
500 stackUsage, err := strconv.Atoi(o)
502 t.Fatalf("Failed to read stack usage: %v", err)
504 if expected, got := 100<<10, stackUsage; got > expected {
505 t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
509 func TestSigStackSwapping(t *testing.T) {
510 switch runtime.GOOS {
511 case "plan9", "windows":
512 t.Skipf("no sigaltstack on %s", runtime.GOOS)
515 got := runTestProg(t, "testprogcgo", "SigStack")
518 t.Errorf("expected %q got %v", want, got)
522 func TestCgoTracebackSigpanic(t *testing.T) {
523 // Test unwinding over a sigpanic in C code without a C
524 // symbolizer. See issue #23576.
525 if runtime.GOOS == "windows" {
526 // On Windows if we get an exception in C code, we let
527 // the Windows exception handler unwind it, rather
528 // than injecting a sigpanic.
529 t.Skip("no sigpanic in C on windows")
532 got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
534 // We should see the function that calls the C function.
535 want := "main.TracebackSigpanic"
536 if !strings.Contains(got, want) {
537 if runtime.GOOS == "android" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
538 testenv.SkipFlaky(t, 58794)
540 t.Errorf("did not see %q in output", want)
542 // We shouldn't inject a sigpanic call. (see issue 57698)
543 nowant := "runtime.sigpanic"
544 if strings.Contains(got, nowant) {
545 t.Errorf("unexpectedly saw %q in output", nowant)
547 // No runtime errors like "runtime: unexpected return pc".
549 if strings.Contains(got, nowant) {
550 t.Errorf("unexpectedly saw %q in output", nowant)
554 func TestCgoPanicCallback(t *testing.T) {
556 got := runTestProg(t, "testprogcgo", "PanicCallback")
558 want := "panic: runtime error: invalid memory address or nil pointer dereference"
559 if !strings.Contains(got, want) {
560 t.Errorf("did not see %q in output", want)
562 want = "panic_callback"
563 if !strings.Contains(got, want) {
564 t.Errorf("did not see %q in output", want)
566 want = "PanicCallback"
567 if !strings.Contains(got, want) {
568 t.Errorf("did not see %q in output", want)
570 // No runtime errors like "runtime: unexpected return pc".
571 nowant := "runtime: "
572 if strings.Contains(got, nowant) {
573 t.Errorf("did not see %q in output", want)
577 // Test that C code called via cgo can use large Windows thread stacks
578 // and call back in to Go without crashing. See issue #20975.
580 // See also TestBigStackCallbackSyscall.
581 func TestBigStackCallbackCgo(t *testing.T) {
582 if runtime.GOOS != "windows" {
583 t.Skip("skipping windows specific test")
586 got := runTestProg(t, "testprogcgo", "BigStack")
589 t.Errorf("expected %q got %v", want, got)
593 func nextTrace(lines []string) ([]string, []string) {
595 for n, line := range lines {
596 if strings.HasPrefix(line, "---") {
597 return trace, lines[n+1:]
599 fields := strings.Fields(strings.TrimSpace(line))
600 if len(fields) == 0 {
603 // Last field contains the function name.
604 trace = append(trace, fields[len(fields)-1])
609 func findTrace(text, top string) []string {
610 lines := strings.Split(text, "\n")
611 _, lines = nextTrace(lines) // Skip the header.
614 t, lines = nextTrace(lines)
625 func TestSegv(t *testing.T) {
626 switch runtime.GOOS {
627 case "plan9", "windows":
628 t.Skipf("no signals on %s", runtime.GOOS)
631 for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} {
634 // The tgkill variants only run on Linux.
635 if runtime.GOOS != "linux" && strings.HasPrefix(test, "Tgkill") {
639 t.Run(test, func(t *testing.T) {
641 got := runTestProg(t, "testprogcgo", test)
644 if !strings.Contains(got, want) {
645 if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" && strings.Contains(got, "fatal: morestack on g0") {
646 testenv.SkipFlaky(t, 39457)
648 t.Errorf("did not see %q in output", want)
651 // No runtime errors like "runtime: unknown pc".
652 switch runtime.GOOS {
653 case "darwin", "illumos", "solaris":
654 // Runtime sometimes throws when generating the traceback.
655 testenv.SkipFlaky(t, 49182)
657 if runtime.GOARCH == "386" {
658 // Runtime throws when generating a traceback from
659 // a VDSO call via asmcgocall.
660 testenv.SkipFlaky(t, 50504)
663 if test == "SegvInCgo" && strings.Contains(got, "unknown pc") {
664 testenv.SkipFlaky(t, 50979)
667 for _, nowant := range []string{"fatal error: ", "runtime: "} {
668 if strings.Contains(got, nowant) {
669 if runtime.GOOS == "darwin" && strings.Contains(got, "0xb01dfacedebac1e") {
670 // See the comment in signal_darwin_amd64.go.
671 t.Skip("skipping due to Darwin handling of malformed addresses")
673 t.Errorf("unexpectedly saw %q in output", nowant)
680 func TestAbortInCgo(t *testing.T) {
681 switch runtime.GOOS {
682 case "plan9", "windows":
683 // N.B. On Windows, C abort() causes the program to exit
684 // without going through the runtime at all.
685 t.Skipf("no signals on %s", runtime.GOOS)
689 got := runTestProg(t, "testprogcgo", "Abort")
692 if !strings.Contains(got, want) {
693 t.Errorf("did not see %q in output", want)
695 // No runtime errors like "runtime: unknown pc".
696 nowant := "runtime: "
697 if strings.Contains(got, nowant) {
698 t.Errorf("did not see %q in output", want)
702 // TestEINTR tests that we handle EINTR correctly.
703 // See issue #20400 and friends.
704 func TestEINTR(t *testing.T) {
705 switch runtime.GOOS {
706 case "plan9", "windows":
707 t.Skipf("no EINTR on %s", runtime.GOOS)
709 if runtime.GOARCH == "386" {
710 // On linux-386 the Go signal handler sets
711 // a restorer function that is not preserved
712 // by the C sigaction call in the test,
713 // causing the signal handler to crash when
714 // returning the normal code. The test is not
715 // architecture-specific, so just skip on 386
716 // rather than doing a complicated workaround.
717 t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
722 output := runTestProg(t, "testprogcgo", "EINTR")
725 t.Fatalf("want %s, got %s\n", want, output)
730 func TestNeedmDeadlock(t *testing.T) {
731 switch runtime.GOOS {
732 case "plan9", "windows":
733 t.Skipf("no signals on %s", runtime.GOOS)
735 output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
738 t.Fatalf("want %s, got %s\n", want, output)
742 func TestCgoTracebackGoroutineProfile(t *testing.T) {
743 output := runTestProg(t, "testprogcgo", "GoroutineProfile")
746 t.Fatalf("want %s, got %s\n", want, output)
750 func TestCgoTraceParser(t *testing.T) {
752 switch runtime.GOOS {
753 case "plan9", "windows":
754 t.Skipf("no pthreads on %s", runtime.GOOS)
756 output := runTestProg(t, "testprogcgo", "CgoTraceParser")
758 ErrTimeOrder := "ErrTimeOrder\n"
759 if output == ErrTimeOrder {
760 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
761 } else if output != want {
762 t.Fatalf("want %s, got %s\n", want, output)
766 func TestCgoTraceParserWithOneProc(t *testing.T) {
768 switch runtime.GOOS {
769 case "plan9", "windows":
770 t.Skipf("no pthreads on %s", runtime.GOOS)
772 output := runTestProg(t, "testprogcgo", "CgoTraceParser", "GOMAXPROCS=1")
774 ErrTimeOrder := "ErrTimeOrder\n"
775 if output == ErrTimeOrder {
776 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
777 } else if output != want {
778 t.Fatalf("GOMAXPROCS=1, want %s, got %s\n", want, output)
782 func TestCgoSigfwd(t *testing.T) {
785 t.Skipf("no signals on %s", runtime.GOOS)
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)
794 func TestDestructorCallback(t *testing.T) {
796 got := runTestProg(t, "testprogcgo", "DestructorCallback")
797 if want := "OK\n"; got != want {
798 t.Errorf("expected %q, but got:\n%s", want, got)
802 func TestDestructorCallbackRace(t *testing.T) {
803 // This test requires building with -race,
804 // so it's somewhat slow.
806 t.Skip("skipping test in -short mode")
809 if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
810 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
815 exe, err := buildTestProg(t, "testprogcgo", "-race")
820 got, err := testenv.CleanCmdEnv(exec.Command(exe, "DestructorCallback")).CombinedOutput()
825 if want := "OK\n"; string(got) != want {
826 t.Errorf("expected %q, but got:\n%s", want, got)