]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/crash_cgo_test.go
20e3b75d79eaf208e61e7db36074ef9c43503c15
[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/platform"
13         "internal/testenv"
14         "os"
15         "os/exec"
16         "runtime"
17         "strconv"
18         "strings"
19         "testing"
20         "time"
21 )
22
23 func TestCgoCrashHandler(t *testing.T) {
24         t.Parallel()
25         testCrashHandler(t, true)
26 }
27
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).
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
43 func 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
52 func 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
79 func 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
91 func 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
105 func 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
122 func 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
134 func 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
148 func 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.
165 func 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
205 func 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
215 func 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
224 func 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
239 func 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
257 func 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
276 func 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
285 func 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
294 func 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
357 func TestCgoPprof(t *testing.T) {
358         testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
359 }
360
361 func TestCgoPprofPIE(t *testing.T) {
362         testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
363 }
364
365 func TestCgoPprofThread(t *testing.T) {
366         testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
367 }
368
369 func TestCgoPprofThreadNoTraceback(t *testing.T) {
370         testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
371 }
372
373 func 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
405 func 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
443 func 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
456 func 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
488 func 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
497 func 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
512 func 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
525 func 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
560 func 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.
587 func 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
599 func 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
615 func 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
631 func 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
694 func 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.
718 func 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.
744 func 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
756 func TestCgoNoCallback(t *testing.T) {
757         got := runTestProg(t, "testprogcgo", "CgoNoCallback")
758         want := "function marked with #cgo nocallback called back into Go"
759         if !strings.Contains(got, want) {
760                 t.Fatalf("did not see %q in output:\n%s", want, got)
761         }
762 }
763
764 func TestCgoNoEscape(t *testing.T) {
765         got := runTestProg(t, "testprogcgo", "CgoNoEscape")
766         want := "OK\n"
767         if got != want {
768                 t.Fatalf("want %s, got %s\n", want, got)
769         }
770 }
771
772 func TestCgoTracebackGoroutineProfile(t *testing.T) {
773         output := runTestProg(t, "testprogcgo", "GoroutineProfile")
774         want := "OK\n"
775         if output != want {
776                 t.Fatalf("want %s, got %s\n", want, output)
777         }
778 }
779
780 func TestCgoTraceParser(t *testing.T) {
781         // Test issue 29707.
782         switch runtime.GOOS {
783         case "plan9", "windows":
784                 t.Skipf("no pthreads on %s", runtime.GOOS)
785         }
786         output := runTestProg(t, "testprogcgo", "CgoTraceParser")
787         want := "OK\n"
788         ErrTimeOrder := "ErrTimeOrder\n"
789         if output == ErrTimeOrder {
790                 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
791         } else if output != want {
792                 t.Fatalf("want %s, got %s\n", want, output)
793         }
794 }
795
796 func TestCgoTraceParserWithOneProc(t *testing.T) {
797         // Test issue 29707.
798         switch runtime.GOOS {
799         case "plan9", "windows":
800                 t.Skipf("no pthreads on %s", runtime.GOOS)
801         }
802         output := runTestProg(t, "testprogcgo", "CgoTraceParser", "GOMAXPROCS=1")
803         want := "OK\n"
804         ErrTimeOrder := "ErrTimeOrder\n"
805         if output == ErrTimeOrder {
806                 t.Skipf("skipping due to golang.org/issue/16755: %v", output)
807         } else if output != want {
808                 t.Fatalf("GOMAXPROCS=1, want %s, got %s\n", want, output)
809         }
810 }
811
812 func TestCgoSigfwd(t *testing.T) {
813         t.Parallel()
814         if !goos.IsUnix {
815                 t.Skipf("no signals on %s", runtime.GOOS)
816         }
817
818         got := runTestProg(t, "testprogcgo", "CgoSigfwd", "GO_TEST_CGOSIGFWD=1")
819         if want := "OK\n"; got != want {
820                 t.Fatalf("expected %q, but got:\n%s", want, got)
821         }
822 }
823
824 func TestDestructorCallback(t *testing.T) {
825         t.Parallel()
826         got := runTestProg(t, "testprogcgo", "DestructorCallback")
827         if want := "OK\n"; got != want {
828                 t.Errorf("expected %q, but got:\n%s", want, got)
829         }
830 }
831
832 func TestDestructorCallbackRace(t *testing.T) {
833         // This test requires building with -race,
834         // so it's somewhat slow.
835         if testing.Short() {
836                 t.Skip("skipping test in -short mode")
837         }
838
839         if !platform.RaceDetectorSupported(runtime.GOOS, runtime.GOARCH) {
840                 t.Skipf("skipping on %s/%s because race detector not supported", runtime.GOOS, runtime.GOARCH)
841         }
842
843         t.Parallel()
844
845         exe, err := buildTestProg(t, "testprogcgo", "-race")
846         if err != nil {
847                 t.Fatal(err)
848         }
849
850         got, err := testenv.CleanCmdEnv(exec.Command(exe, "DestructorCallback")).CombinedOutput()
851         if err != nil {
852                 t.Fatal(err)
853         }
854
855         if want := "OK\n"; string(got) != want {
856                 t.Errorf("expected %q, but got:\n%s", want, got)
857         }
858 }
859
860 func TestEnsureBindM(t *testing.T) {
861         t.Parallel()
862         switch runtime.GOOS {
863         case "windows", "plan9":
864                 t.Skipf("skipping bindm test on %s", runtime.GOOS)
865         }
866         got := runTestProg(t, "testprogcgo", "EnsureBindM")
867         want := "OK\n"
868         if got != want {
869                 t.Errorf("expected %q, got %v", want, got)
870         }
871 }
872
873 func TestStackSwitchCallback(t *testing.T) {
874         t.Parallel()
875         switch runtime.GOOS {
876         case "windows", "plan9", "android", "ios", "openbsd": // no getcontext
877                 t.Skipf("skipping test on %s", runtime.GOOS)
878         }
879         got := runTestProg(t, "testprogcgo", "StackSwitchCallback")
880         skip := "SKIP\n"
881         if got == skip {
882                 t.Skip("skipping on musl/bionic libc")
883         }
884         want := "OK\n"
885         if got != want {
886                 t.Errorf("expected %q, got %v", want, got)
887         }
888 }