]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/crash_cgo_test.go
c6c018ccdf17f29b98e9ac00b714492e18cadfc8
[gostls13.git] / src / runtime / crash_cgo_test.go
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
7 package runtime_test
8
9 import (
10         "fmt"
11         "internal/goos"
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         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")
70         }
71         got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
72         want := "OK\n"
73         if got != want {
74                 t.Fatalf("expected %q, but got:\n%s", want, got)
75         }
76 }
77
78 func TestCgoExternalThreadPanic(t *testing.T) {
79         t.Parallel()
80         if runtime.GOOS == "plan9" {
81                 t.Skipf("no pthreads on %s", runtime.GOOS)
82         }
83         got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
84         want := "panic: BOOM"
85         if !strings.Contains(got, want) {
86                 t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
87         }
88 }
89
90 func TestCgoExternalThreadSIGPROF(t *testing.T) {
91         t.Parallel()
92         // issue 9456.
93         switch runtime.GOOS {
94         case "plan9", "windows":
95                 t.Skipf("no pthreads on %s", runtime.GOOS)
96         }
97
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)
101         }
102 }
103
104 func TestCgoExternalThreadSignal(t *testing.T) {
105         t.Parallel()
106         // issue 10139
107         switch runtime.GOOS {
108         case "plan9", "windows":
109                 t.Skipf("no pthreads on %s", runtime.GOOS)
110         }
111
112         got := runTestProg(t, "testprogcgo", "CgoExternalThreadSignal")
113         if want := "OK\n"; got != want {
114                 t.Fatalf("expected %q, but got:\n%s", want, got)
115         }
116 }
117
118 func TestCgoDLLImports(t *testing.T) {
119         // test issue 9356
120         if runtime.GOOS != "windows" {
121                 t.Skip("skipping windows specific test")
122         }
123         got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
124         want := "OK\n"
125         if got != want {
126                 t.Fatalf("expected %q, but got %v", want, got)
127         }
128 }
129
130 func TestCgoExecSignalMask(t *testing.T) {
131         t.Parallel()
132         // Test issue 13164.
133         switch runtime.GOOS {
134         case "windows", "plan9":
135                 t.Skipf("skipping signal mask test on %s", runtime.GOOS)
136         }
137         got := runTestProg(t, "testprogcgo", "CgoExecSignalMask", "GOTRACEBACK=system")
138         want := "OK\n"
139         if got != want {
140                 t.Errorf("expected %q, got %v", want, got)
141         }
142 }
143
144 func TestEnsureDropM(t *testing.T) {
145         t.Parallel()
146         // Test for issue 13881.
147         switch runtime.GOOS {
148         case "windows", "plan9":
149                 t.Skipf("skipping dropm test on %s", runtime.GOOS)
150         }
151         got := runTestProg(t, "testprogcgo", "EnsureDropM")
152         want := "OK\n"
153         if got != want {
154                 t.Errorf("expected %q, got %v", want, got)
155         }
156 }
157
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) {
162         t.Parallel()
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")
166         if err != nil {
167                 t.Fatal(err)
168         }
169
170         // Try it 10 times to avoid flakiness.
171         const tries = 10
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))
176
177                 start := time.Now()
178                 cmd.Run()
179                 d1 := time.Since(start)
180
181                 cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
182                 cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
183
184                 start = time.Now()
185                 cmd.Run()
186                 d2 := time.Since(start)
187
188                 if d1*20 > d2 {
189                         // The slow version (d2) was less than 20 times
190                         // slower than the fast version (d1), so OK.
191                         return
192                 }
193
194                 tot1 += d1
195                 tot2 += d2
196         }
197
198         t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
199 }
200
201 func TestCgoPanicDeadlock(t *testing.T) {
202         t.Parallel()
203         // test issue 14432
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)
208         }
209 }
210
211 func TestCgoCCodeSIGPROF(t *testing.T) {
212         t.Parallel()
213         got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
214         want := "OK\n"
215         if got != want {
216                 t.Errorf("expected %q got %v", want, got)
217         }
218 }
219
220 func TestCgoPprofCallback(t *testing.T) {
221         if testing.Short() {
222                 t.Skip("skipping in short mode") // takes a full second
223         }
224         switch runtime.GOOS {
225         case "windows", "plan9":
226                 t.Skipf("skipping cgo pprof callback test on %s", runtime.GOOS)
227         }
228         got := runTestProg(t, "testprogcgo", "CgoPprofCallback")
229         want := "OK\n"
230         if got != want {
231                 t.Errorf("expected %q got %v", want, got)
232         }
233 }
234
235 func TestCgoCrashTraceback(t *testing.T) {
236         t.Parallel()
237         switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
238         case "darwin/amd64":
239         case "linux/amd64":
240         case "linux/arm64":
241         case "linux/ppc64le":
242         default:
243                 t.Skipf("not yet supported on %s", platform)
244         }
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)
249                 }
250         }
251 }
252
253 func TestCgoCrashTracebackGo(t *testing.T) {
254         t.Parallel()
255         switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
256         case "darwin/amd64":
257         case "linux/amd64":
258         case "linux/arm64":
259         case "linux/ppc64le":
260         default:
261                 t.Skipf("not yet supported on %s", platform)
262         }
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)
268                 }
269         }
270 }
271
272 func TestCgoTracebackContext(t *testing.T) {
273         t.Parallel()
274         got := runTestProg(t, "testprogcgo", "TracebackContext")
275         want := "OK\n"
276         if got != want {
277                 t.Errorf("expected %q got %v", want, got)
278         }
279 }
280
281 func TestCgoTracebackContextPreemption(t *testing.T) {
282         t.Parallel()
283         got := runTestProg(t, "testprogcgo", "TracebackContextPreemption")
284         want := "OK\n"
285         if got != want {
286                 t.Errorf("expected %q got %v", want, got)
287         }
288 }
289
290 func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
291         t.Parallel()
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)
294         }
295         testenv.MustHaveGoRun(t)
296
297         exe, err := buildTestProg(t, "testprogcgo", buildArg)
298         if err != nil {
299                 t.Fatal(err)
300         }
301
302         cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg))
303         got, err := cmd.CombinedOutput()
304         if err != nil {
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)
308                 }
309                 t.Fatalf("%s\n\n%v", got, err)
310         }
311         fn := strings.TrimSpace(string(got))
312         defer os.Remove(fn)
313
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.
317                 if try == 0 {
318                         cmd.Args = append(cmd.Args, exe, fn)
319                 } else {
320                         cmd.Args = append(cmd.Args, fn)
321                 }
322
323                 found := false
324                 for i, e := range cmd.Env {
325                         if strings.HasPrefix(e, "PPROF_TMPDIR=") {
326                                 cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
327                                 found = true
328                                 break
329                         }
330                 }
331                 if !found {
332                         cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
333                 }
334
335                 out, err := cmd.CombinedOutput()
336                 t.Logf("%s:\n%s", cmd.Args, out)
337                 if err != nil {
338                         t.Error(err)
339                         continue
340                 }
341
342                 trace := findTrace(string(out), top)
343                 if len(trace) == 0 {
344                         t.Errorf("%s traceback missing.", top)
345                         continue
346                 }
347                 if trace[len(trace)-1] != bottom {
348                         t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
349                 }
350         }
351 }
352
353 func TestCgoPprof(t *testing.T) {
354         testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
355 }
356
357 func TestCgoPprofPIE(t *testing.T) {
358         testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
359 }
360
361 func TestCgoPprofThread(t *testing.T) {
362         testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
363 }
364
365 func TestCgoPprofThreadNoTraceback(t *testing.T) {
366         testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
367 }
368
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)
372         }
373
374         testenv.MustHaveGoRun(t)
375
376         // This test requires building various packages with -race, so
377         // it's somewhat slow.
378         if testing.Short() {
379                 t.Skip("skipping test in -short mode")
380         }
381
382         exe, err := buildTestProg(t, "testprogcgo", "-race")
383         if err != nil {
384                 t.Fatal(err)
385         }
386
387         got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
388         if err != nil {
389                 t.Fatal(err)
390         }
391         want := "OK\n"
392         if string(got) != want {
393                 t.Errorf("expected %q got %s", want, got)
394         }
395 }
396
397 func TestRaceSignal(t *testing.T) {
398         t.Parallel()
399         if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
400                 t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
401         }
402
403         testenv.MustHaveGoRun(t)
404
405         // This test requires building various packages with -race, so
406         // it's somewhat slow.
407         if testing.Short() {
408                 t.Skip("skipping test in -short mode")
409         }
410
411         exe, err := buildTestProg(t, "testprogcgo", "-race")
412         if err != nil {
413                 t.Fatal(err)
414         }
415
416         got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
417         if err != nil {
418                 t.Logf("%s\n", got)
419                 t.Fatal(err)
420         }
421         want := "OK\n"
422         if string(got) != want {
423                 t.Errorf("expected %q got %s", want, got)
424         }
425 }
426
427 func TestCgoNumGoroutine(t *testing.T) {
428         switch runtime.GOOS {
429         case "windows", "plan9":
430                 t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
431         }
432         t.Parallel()
433         got := runTestProg(t, "testprogcgo", "NumGoroutine")
434         want := "OK\n"
435         if got != want {
436                 t.Errorf("expected %q got %v", want, got)
437         }
438 }
439
440 func TestCatchPanic(t *testing.T) {
441         t.Parallel()
442         switch runtime.GOOS {
443         case "plan9", "windows":
444                 t.Skipf("no signals on %s", runtime.GOOS)
445         case "darwin":
446                 if runtime.GOARCH == "amd64" {
447                         t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
448                 }
449         }
450
451         testenv.MustHaveGoRun(t)
452
453         exe, err := buildTestProg(t, "testprogcgo")
454         if err != nil {
455                 t.Fatal(err)
456         }
457
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")
462                 if early {
463                         // Tell testprogcgo to install an early signal handler for SIGABRT
464                         cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
465                 }
466                 if out, err := cmd.CombinedOutput(); err != nil {
467                         t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
468                 }
469         }
470 }
471
472 func TestCgoLockOSThreadExit(t *testing.T) {
473         switch runtime.GOOS {
474         case "plan9", "windows":
475                 t.Skipf("no pthreads on %s", runtime.GOOS)
476         }
477         t.Parallel()
478         testLockOSThreadExit(t, "testprogcgo")
479 }
480
481 func TestWindowsStackMemoryCgo(t *testing.T) {
482         if runtime.GOOS != "windows" {
483                 t.Skip("skipping windows specific test")
484         }
485         testenv.SkipFlaky(t, 22575)
486         o := runTestProg(t, "testprogcgo", "StackMemory")
487         stackUsage, err := strconv.Atoi(o)
488         if err != nil {
489                 t.Fatalf("Failed to read stack usage: %v", err)
490         }
491         if expected, got := 100<<10, stackUsage; got > expected {
492                 t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
493         }
494 }
495
496 func TestSigStackSwapping(t *testing.T) {
497         switch runtime.GOOS {
498         case "plan9", "windows":
499                 t.Skipf("no sigaltstack on %s", runtime.GOOS)
500         }
501         t.Parallel()
502         got := runTestProg(t, "testprogcgo", "SigStack")
503         want := "OK\n"
504         if got != want {
505                 t.Errorf("expected %q got %v", want, got)
506         }
507 }
508
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")
517         }
518         t.Parallel()
519         got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
520         t.Log(got)
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)
526                 }
527                 t.Errorf("did not see %q in output", want)
528         }
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)
533         }
534         // No runtime errors like "runtime: unexpected return pc".
535         nowant = "runtime: "
536         if strings.Contains(got, nowant) {
537                 t.Errorf("unexpectedly saw %q in output", nowant)
538         }
539 }
540
541 func TestCgoPanicCallback(t *testing.T) {
542         t.Parallel()
543         got := runTestProg(t, "testprogcgo", "PanicCallback")
544         t.Log(got)
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)
548         }
549         want = "panic_callback"
550         if !strings.Contains(got, want) {
551                 t.Errorf("did not see %q in output", want)
552         }
553         want = "PanicCallback"
554         if !strings.Contains(got, want) {
555                 t.Errorf("did not see %q in output", want)
556         }
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)
561         }
562 }
563
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.
566 //
567 // See also TestBigStackCallbackSyscall.
568 func TestBigStackCallbackCgo(t *testing.T) {
569         if runtime.GOOS != "windows" {
570                 t.Skip("skipping windows specific test")
571         }
572         t.Parallel()
573         got := runTestProg(t, "testprogcgo", "BigStack")
574         want := "OK\n"
575         if got != want {
576                 t.Errorf("expected %q got %v", want, got)
577         }
578 }
579
580 func nextTrace(lines []string) ([]string, []string) {
581         var trace []string
582         for n, line := range lines {
583                 if strings.HasPrefix(line, "---") {
584                         return trace, lines[n+1:]
585                 }
586                 fields := strings.Fields(strings.TrimSpace(line))
587                 if len(fields) == 0 {
588                         continue
589                 }
590                 // Last field contains the function name.
591                 trace = append(trace, fields[len(fields)-1])
592         }
593         return nil, nil
594 }
595
596 func findTrace(text, top string) []string {
597         lines := strings.Split(text, "\n")
598         _, lines = nextTrace(lines) // Skip the header.
599         for len(lines) > 0 {
600                 var t []string
601                 t, lines = nextTrace(lines)
602                 if len(t) == 0 {
603                         continue
604                 }
605                 if t[0] == top {
606                         return t
607                 }
608         }
609         return nil
610 }
611
612 func TestSegv(t *testing.T) {
613         switch runtime.GOOS {
614         case "plan9", "windows":
615                 t.Skipf("no signals on %s", runtime.GOOS)
616         }
617
618         for _, test := range []string{"Segv", "SegvInCgo", "TgkillSegv", "TgkillSegvInCgo"} {
619                 test := test
620
621                 // The tgkill variants only run on Linux.
622                 if runtime.GOOS != "linux" && strings.HasPrefix(test, "Tgkill") {
623                         continue
624                 }
625
626                 t.Run(test, func(t *testing.T) {
627                         t.Parallel()
628                         got := runTestProg(t, "testprogcgo", test)
629                         t.Log(got)
630                         want := "SIGSEGV"
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)
634                                 }
635                                 t.Errorf("did not see %q in output", want)
636                         }
637
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)
643                         case "linux":
644                                 if runtime.GOARCH == "386" {
645                                         // Runtime throws when generating a traceback from
646                                         // a VDSO call via asmcgocall.
647                                         testenv.SkipFlaky(t, 50504)
648                                 }
649                         }
650                         if test == "SegvInCgo" && strings.Contains(got, "unknown pc") {
651                                 testenv.SkipFlaky(t, 50979)
652                         }
653
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")
659                                         }
660                                         t.Errorf("unexpectedly saw %q in output", nowant)
661                                 }
662                         }
663                 })
664         }
665 }
666
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)
673         }
674
675         t.Parallel()
676         got := runTestProg(t, "testprogcgo", "Abort")
677         t.Log(got)
678         want := "SIGABRT"
679         if !strings.Contains(got, want) {
680                 t.Errorf("did not see %q in output", want)
681         }
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)
686         }
687 }
688
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)
695         case "linux":
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")
705                 }
706         }
707
708         t.Parallel()
709         output := runTestProg(t, "testprogcgo", "EINTR")
710         want := "OK\n"
711         if output != want {
712                 t.Fatalf("want %s, got %s\n", want, output)
713         }
714 }
715
716 // Issue #42207.
717 func TestNeedmDeadlock(t *testing.T) {
718         switch runtime.GOOS {
719         case "plan9", "windows":
720                 t.Skipf("no signals on %s", runtime.GOOS)
721         }
722         output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
723         want := "OK\n"
724         if output != want {
725                 t.Fatalf("want %s, got %s\n", want, output)
726         }
727 }
728
729 func TestCgoTracebackGoroutineProfile(t *testing.T) {
730         output := runTestProg(t, "testprogcgo", "GoroutineProfile")
731         want := "OK\n"
732         if output != want {
733                 t.Fatalf("want %s, got %s\n", want, output)
734         }
735 }
736
737 func TestCgoTraceParser(t *testing.T) {
738         // Test issue 29707.
739         switch runtime.GOOS {
740         case "plan9", "windows":
741                 t.Skipf("no pthreads on %s", runtime.GOOS)
742         }
743         output := runTestProg(t, "testprogcgo", "CgoTraceParser")
744         want := "OK\n"
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)
750         }
751 }
752
753 func TestCgoTraceParserWithOneProc(t *testing.T) {
754         // Test issue 29707.
755         switch runtime.GOOS {
756         case "plan9", "windows":
757                 t.Skipf("no pthreads on %s", runtime.GOOS)
758         }
759         output := runTestProg(t, "testprogcgo", "CgoTraceParser", "GOMAXPROCS=1")
760         want := "OK\n"
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)
766         }
767 }
768
769 func TestCgoSigfwd(t *testing.T) {
770         t.Parallel()
771         if !goos.IsUnix {
772                 t.Skipf("no signals on %s", runtime.GOOS)
773         }
774
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)
778         }
779 }