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.
22 func TestCgoCrashHandler(t *testing.T) {
24 testCrashHandler(t, true)
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).
32 if testing.Short() && runtime.GOOS == "windows" {
33 t.Skip("Skipping in short mode") // takes up to 64 seconds
35 got := runTestProg(t, "testprogcgo", "CgoSignalDeadlock")
38 t.Fatalf("expected %q, but got:\n%s", want, got)
42 func TestCgoTraceback(t *testing.T) {
44 got := runTestProg(t, "testprogcgo", "CgoTraceback")
47 t.Fatalf("expected %q, but got:\n%s", want, got)
51 func TestCgoCallbackGC(t *testing.T) {
54 case "plan9", "windows":
55 t.Skipf("no pthreads on %s", runtime.GOOS)
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")
67 if testenv.Builder() == "darwin-amd64-10_14" {
68 // TODO(#23011): When the 10.14 builders are gone, remove this skip.
69 t.Skip("skipping due to platform bug on macOS 10.14; see https://golang.org/issue/43926")
71 got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
74 t.Fatalf("expected %q, but got:\n%s", want, got)
78 func TestCgoExternalThreadPanic(t *testing.T) {
80 if runtime.GOOS == "plan9" {
81 t.Skipf("no pthreads on %s", runtime.GOOS)
83 got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
85 if !strings.Contains(got, want) {
86 t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
90 func TestCgoExternalThreadSIGPROF(t *testing.T) {
94 case "plan9", "windows":
95 t.Skipf("no pthreads on %s", runtime.GOOS)
98 got := runTestProg(t, "testprogcgo", "CgoExternalThreadSIGPROF", "GO_START_SIGPROF_THREAD=1")
99 if want := "OK\n"; got != want {
100 t.Fatalf("expected %q, but got:\n%s", want, got)
104 func TestCgoExternalThreadSignal(t *testing.T) {
107 switch runtime.GOOS {
108 case "plan9", "windows":
109 t.Skipf("no pthreads on %s", runtime.GOOS)
112 got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
113 if want := "OK\n"; got != want {
114 t.Fatalf("expected %q, but got:\n%s", want, got)
118 func TestCgoDLLImports(t *testing.T) {
120 if runtime.GOOS != "windows" {
121 t.Skip("skipping windows specific test")
123 got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
126 t.Fatalf("expected %q, but got %v", want, got)
130 func TestCgoExecSignalMask(t *testing.T) {
133 switch runtime.GOOS {
134 case "windows", "plan9":
135 t.Skipf("skipping signal mask test on %s", runtime.GOOS)
137 got := runTestProg(t, "testprogcgo", "CgoExecSignalMask", "GOTRACEBACK=system")
140 t.Errorf("expected %q, got %v", want, got)
144 func TestEnsureDropM(t *testing.T) {
146 // Test for issue 13881.
147 switch runtime.GOOS {
148 case "windows", "plan9":
149 t.Skipf("skipping dropm test on %s", runtime.GOOS)
151 got := runTestProg(t, "testprogcgo", "EnsureDropM")
154 t.Errorf("expected %q, got %v", want, got)
158 // Test for issue 14387.
159 // Test that the program that doesn't need any cgo pointer checking
160 // takes about the same amount of time with it as without it.
161 func TestCgoCheckBytes(t *testing.T) {
163 // Make sure we don't count the build time as part of the run time.
164 testenv.MustHaveGoBuild(t)
165 exe, err := buildTestProg(t, "testprogcgo")
170 // Try it 10 times to avoid flakiness.
172 var tot1, tot2 time.Duration
173 for i := 0; i < tries; i++ {
174 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
175 cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
179 d1 := time.Since(start)
181 cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
182 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
186 d2 := time.Since(start)
189 // The slow version (d2) was less than 20 times
190 // slower than the fast version (d1), so OK.
198 t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
201 func TestCgoPanicDeadlock(t *testing.T) {
204 got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
205 want := "panic: cgo error\n\n"
206 if !strings.HasPrefix(got, want) {
207 t.Fatalf("output does not start with %q:\n%s", want, got)
211 func TestCgoCCodeSIGPROF(t *testing.T) {
213 got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
216 t.Errorf("expected %q got %v", want, got)
220 func TestCgoPprofCallback(t *testing.T) {
222 t.Skip("skipping in short mode") // takes a full second
224 switch runtime.GOOS {
225 case "windows", "plan9":
226 t.Skipf("skipping cgo pprof callback test on %s", runtime.GOOS)
228 got := runTestProg(t, "testprogcgo", "CgoPprofCallback")
231 t.Errorf("expected %q got %v", want, got)
235 func TestCgoCrashTraceback(t *testing.T) {
237 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
241 case "linux/ppc64le":
243 t.Skipf("not yet supported on %s", platform)
245 got := runTestProg(t, "testprogcgo", "CrashTraceback")
246 for i := 1; i <= 3; i++ {
247 if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
248 t.Errorf("missing cgo symbolizer:%d", i)
253 func TestCgoCrashTracebackGo(t *testing.T) {
255 switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
259 case "linux/ppc64le":
261 t.Skipf("not yet supported on %s", platform)
263 got := runTestProg(t, "testprogcgo", "CrashTracebackGo")
264 for i := 1; i <= 3; i++ {
265 want := fmt.Sprintf("main.h%d", i)
266 if !strings.Contains(got, want) {
267 t.Errorf("missing %s", want)
272 func TestCgoTracebackContext(t *testing.T) {
274 got := runTestProg(t, "testprogcgo", "TracebackContext")
277 t.Errorf("expected %q got %v", want, got)
281 func TestCgoTracebackContextPreemption(t *testing.T) {
283 got := runTestProg(t, "testprogcgo", "TracebackContextPreemption")
286 t.Errorf("expected %q got %v", want, got)
290 func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
292 if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le" && runtime.GOARCH != "arm64") {
293 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
295 testenv.MustHaveGoRun(t)
297 exe, err := buildTestProg(t, "testprogcgo", buildArg)
302 cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg))
303 got, err := cmd.CombinedOutput()
305 if testenv.Builder() == "linux-amd64-alpine" {
306 // See Issue 18243 and Issue 19938.
307 t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
309 t.Fatalf("%s\n\n%v", got, err)
311 fn := strings.TrimSpace(string(got))
314 for try := 0; try < 2; try++ {
315 cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-tagignore=ignore", "-traces"))
316 // Check that pprof works both with and without explicit executable on command line.
318 cmd.Args = append(cmd.Args, exe, fn)
320 cmd.Args = append(cmd.Args, fn)
324 for i, e := range cmd.Env {
325 if strings.HasPrefix(e, "PPROF_TMPDIR=") {
326 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
332 cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
335 out, err := cmd.CombinedOutput()
336 t.Logf("%s:\n%s", cmd.Args, out)
342 trace := findTrace(string(out), top)
344 t.Errorf("%s traceback missing.", top)
347 if trace[len(trace)-1] != bottom {
348 t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
353 func TestCgoPprof(t *testing.T) {
354 testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
357 func TestCgoPprofPIE(t *testing.T) {
358 testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
361 func TestCgoPprofThread(t *testing.T) {
362 testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
365 func TestCgoPprofThreadNoTraceback(t *testing.T) {
366 testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
369 func TestRaceProf(t *testing.T) {
370 if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
371 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
374 testenv.MustHaveGoRun(t)
376 // This test requires building various packages with -race, so
377 // it's somewhat slow.
379 t.Skip("skipping test in -short mode")
382 exe, err := buildTestProg(t, "testprogcgo", "-race")
387 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
392 if string(got) != want {
393 t.Errorf("expected %q got %s", want, got)
397 func TestRaceSignal(t *testing.T) {
399 if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
400 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
403 testenv.MustHaveGoRun(t)
405 // This test requires building various packages with -race, so
406 // it's somewhat slow.
408 t.Skip("skipping test in -short mode")
411 exe, err := buildTestProg(t, "testprogcgo", "-race")
416 got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
422 if string(got) != want {
423 t.Errorf("expected %q got %s", want, got)
427 func TestCgoNumGoroutine(t *testing.T) {
428 switch runtime.GOOS {
429 case "windows", "plan9":
430 t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
433 got := runTestProg(t, "testprogcgo", "NumGoroutine")
436 t.Errorf("expected %q got %v", want, got)
440 func TestCatchPanic(t *testing.T) {
442 switch runtime.GOOS {
443 case "plan9", "windows":
444 t.Skipf("no signals on %s", runtime.GOOS)
446 if runtime.GOARCH == "amd64" {
447 t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
451 testenv.MustHaveGoRun(t)
453 exe, err := buildTestProg(t, "testprogcgo")
458 for _, early := range []bool{true, false} {
459 cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
460 // Make sure a panic results in a crash.
461 cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
463 // Tell testprogcgo to install an early signal handler for SIGABRT
464 cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
466 if out, err := cmd.CombinedOutput(); err != nil {
467 t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
472 func TestCgoLockOSThreadExit(t *testing.T) {
473 switch runtime.GOOS {
474 case "plan9", "windows":
475 t.Skipf("no pthreads on %s", runtime.GOOS)
478 testLockOSThreadExit(t, "testprogcgo")
481 func TestWindowsStackMemoryCgo(t *testing.T) {
482 if runtime.GOOS != "windows" {
483 t.Skip("skipping windows specific test")
485 testenv.SkipFlaky(t, 22575)
486 o := runTestProg(t, "testprogcgo", "StackMemory")
487 stackUsage, err := strconv.Atoi(o)
489 t.Fatalf("Failed to read stack usage: %v", err)
491 if expected, got := 100<<10, stackUsage; got > expected {
492 t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
496 func TestSigStackSwapping(t *testing.T) {
497 switch runtime.GOOS {
498 case "plan9", "windows":
499 t.Skipf("no sigaltstack on %s", runtime.GOOS)
502 got := runTestProg(t, "testprogcgo", "SigStack")
505 t.Errorf("expected %q got %v", want, got)
509 func TestCgoTracebackSigpanic(t *testing.T) {
510 // Test unwinding over a sigpanic in C code without a C
511 // symbolizer. See issue #23576.
512 if runtime.GOOS == "windows" {
513 // On Windows if we get an exception in C code, we let
514 // the Windows exception handler unwind it, rather
515 // than injecting a sigpanic.
516 t.Skip("no sigpanic in C on windows")
519 got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
521 // We should see the function that calls the C function.
522 want := "main.TracebackSigpanic"
523 if !strings.Contains(got, want) {
524 if runtime.GOOS == "android" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
525 testenv.SkipFlaky(t, 58794)
527 t.Errorf("did not see %q in output", want)
529 // We shouldn't inject a sigpanic call. (see issue 57698)
530 nowant := "runtime.sigpanic"
531 if strings.Contains(got, nowant) {
532 t.Errorf("unexpectedly saw %q in output", nowant)
534 // No runtime errors like "runtime: unexpected return pc".
536 if strings.Contains(got, nowant) {
537 t.Errorf("unexpectedly saw %q in output", nowant)
541 func TestCgoPanicCallback(t *testing.T) {
543 got := runTestProg(t, "testprogcgo", "PanicCallback")
545 want := "panic: runtime error: invalid memory address or nil pointer dereference"
546 if !strings.Contains(got, want) {
547 t.Errorf("did not see %q in output", want)
549 want = "panic_callback"
550 if !strings.Contains(got, want) {
551 t.Errorf("did not see %q in output", want)
553 want = "PanicCallback"
554 if !strings.Contains(got, want) {
555 t.Errorf("did not see %q in output", want)
557 // No runtime errors like "runtime: unexpected return pc".
558 nowant := "runtime: "
559 if strings.Contains(got, nowant) {
560 t.Errorf("did not see %q in output", want)
564 // Test that C code called via cgo can use large Windows thread stacks
565 // and call back in to Go without crashing. See issue #20975.
567 // See also TestBigStackCallbackSyscall.
568 func TestBigStackCallbackCgo(t *testing.T) {
569 if runtime.GOOS != "windows" {
570 t.Skip("skipping windows specific test")
573 got := runTestProg(t, "testprogcgo", "BigStack")
576 t.Errorf("expected %q got %v", want, got)
580 func nextTrace(lines []string) ([]string, []string) {
582 for n, line := range lines {
583 if strings.HasPrefix(line, "---") {
584 return trace, lines[n+1:]
586 fields := strings.Fields(strings.TrimSpace(line))
587 if len(fields) == 0 {
590 // Last field contains the function name.
591 trace = append(trace, fields[len(fields)-1])
596 func findTrace(text, top string) []string {
597 lines := strings.Split(text, "\n")
598 _, lines = nextTrace(lines) // Skip the header.
601 t, lines = nextTrace(lines)
612 func TestSegv(t *testing.T) {
613 switch runtime.GOOS {
614 case "plan9", "windows":
615 t.Skipf("no signals on %s", runtime.GOOS)
618 for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} {
621 // The tgkill variants only run on Linux.
622 if runtime.GOOS != "linux" && strings.HasPrefix(test, "Tgkill") {
626 t.Run(test, func(t *testing.T) {
628 got := runTestProg(t, "testprogcgo", test)
631 if !strings.Contains(got, want) {
632 if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" && strings.Contains(got, "fatal: morestack on g0") {
633 testenv.SkipFlaky(t, 39457)
635 t.Errorf("did not see %q in output", want)
638 // No runtime errors like "runtime: unknown pc".
639 switch runtime.GOOS {
640 case "darwin", "illumos", "solaris":
641 // Runtime sometimes throws when generating the traceback.
642 testenv.SkipFlaky(t, 49182)
644 if runtime.GOARCH == "386" {
645 // Runtime throws when generating a traceback from
646 // a VDSO call via asmcgocall.
647 testenv.SkipFlaky(t, 50504)
650 if test == "SegvInCgo" && strings.Contains(got, "unknown pc") {
651 testenv.SkipFlaky(t, 50979)
654 for _, nowant := range []string{"fatal error: ", "runtime: "} {
655 if strings.Contains(got, nowant) {
656 if runtime.GOOS == "darwin" && strings.Contains(got, "0xb01dfacedebac1e") {
657 // See the comment in signal_darwin_amd64.go.
658 t.Skip("skipping due to Darwin handling of malformed addresses")
660 t.Errorf("unexpectedly saw %q in output", nowant)
667 func TestAbortInCgo(t *testing.T) {
668 switch runtime.GOOS {
669 case "plan9", "windows":
670 // N.B. On Windows, C abort() causes the program to exit
671 // without going through the runtime at all.
672 t.Skipf("no signals on %s", runtime.GOOS)
676 got := runTestProg(t, "testprogcgo", "Abort")
679 if !strings.Contains(got, want) {
680 t.Errorf("did not see %q in output", want)
682 // No runtime errors like "runtime: unknown pc".
683 nowant := "runtime: "
684 if strings.Contains(got, nowant) {
685 t.Errorf("did not see %q in output", want)
689 // TestEINTR tests that we handle EINTR correctly.
690 // See issue #20400 and friends.
691 func TestEINTR(t *testing.T) {
692 switch runtime.GOOS {
693 case "plan9", "windows":
694 t.Skipf("no EINTR on %s", runtime.GOOS)
696 if runtime.GOARCH == "386" {
697 // On linux-386 the Go signal handler sets
698 // a restorer function that is not preserved
699 // by the C sigaction call in the test,
700 // causing the signal handler to crash when
701 // returning the normal code. The test is not
702 // architecture-specific, so just skip on 386
703 // rather than doing a complicated workaround.
704 t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
709 output := runTestProg(t, "testprogcgo", "EINTR")
712 t.Fatalf("want %s, got %s\n", want, output)
717 func TestNeedmDeadlock(t *testing.T) {
718 switch runtime.GOOS {
719 case "plan9", "windows":
720 t.Skipf("no signals on %s", runtime.GOOS)
722 output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
725 t.Fatalf("want %s, got %s\n", want, output)
729 func TestCgoTracebackGoroutineProfile(t *testing.T) {
730 output := runTestProg(t, "testprogcgo", "GoroutineProfile")
733 t.Fatalf("want %s, got %s\n", want, output)
737 func TestCgoTraceParser(t *testing.T) {
739 switch runtime.GOOS {
740 case "plan9", "windows":
741 t.Skipf("no pthreads on %s", runtime.GOOS)
743 output := runTestProg(t, "testprogcgo", "CgoTraceParser")
745 ErrTimeOrder := "ErrTimeOrder\n"
746 if output == ErrTimeOrder {
747 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
748 } else if output != want {
749 t.Fatalf("want %s, got %s\n", want, output)
753 func TestCgoTraceParserWithOneProc(t *testing.T) {
755 switch runtime.GOOS {
756 case "plan9", "windows":
757 t.Skipf("no pthreads on %s", runtime.GOOS)
759 output := runTestProg(t, "testprogcgo", "CgoTraceParser", "GOMAXPROCS=1")
761 ErrTimeOrder := "ErrTimeOrder\n"
762 if output == ErrTimeOrder {
763 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
764 } else if output != want {
765 t.Fatalf("GOMAXPROCS=1, want %s, got %s\n", want, output)
769 func TestCgoSigfwd(t *testing.T) {
772 t.Skipf("no signals on %s", runtime.GOOS)
775 got := runTestProg(t, "testprogcgo", "CgoSigfwd", "GO_TEST_CGOSIGFWD=1")
776 if want := "OK\n"; got != want {
777 t.Fatalf("expected %q, but got:\n%s", want, got)