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

View as plain text