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/ppc64le":
   238  	default:
   239  		t.Skipf("not yet supported on %s", platform)
   240  	}
   241  	got := runTestProg(t, "testprogcgo", "CrashTraceback")
   242  	for i := 1; i <= 3; i++ {
   243  		if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
   244  			t.Errorf("missing cgo symbolizer:%d", i)
   245  		}
   246  	}
   247  }
   248  
   249  func TestCgoCrashTracebackGo(t *testing.T) {
   250  	t.Parallel()
   251  	switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
   252  	case "darwin/amd64":
   253  	case "linux/amd64":
   254  	case "linux/ppc64le":
   255  	default:
   256  		t.Skipf("not yet supported on %s", platform)
   257  	}
   258  	got := runTestProg(t, "testprogcgo", "CrashTracebackGo")
   259  	for i := 1; i <= 3; i++ {
   260  		want := fmt.Sprintf("main.h%d", i)
   261  		if !strings.Contains(got, want) {
   262  			t.Errorf("missing %s", want)
   263  		}
   264  	}
   265  }
   266  
   267  func TestCgoTracebackContext(t *testing.T) {
   268  	t.Parallel()
   269  	got := runTestProg(t, "testprogcgo", "TracebackContext")
   270  	want := "OK\n"
   271  	if got != want {
   272  		t.Errorf("expected %q got %v", want, got)
   273  	}
   274  }
   275  
   276  func TestCgoTracebackContextPreemption(t *testing.T) {
   277  	t.Parallel()
   278  	got := runTestProg(t, "testprogcgo", "TracebackContextPreemption")
   279  	want := "OK\n"
   280  	if got != want {
   281  		t.Errorf("expected %q got %v", want, got)
   282  	}
   283  }
   284  
   285  func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
   286  	t.Parallel()
   287  	if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
   288  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   289  	}
   290  	testenv.MustHaveGoRun(t)
   291  
   292  	exe, err := buildTestProg(t, "testprogcgo", buildArg)
   293  	if err != nil {
   294  		t.Fatal(err)
   295  	}
   296  
   297  	cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg))
   298  	got, err := cmd.CombinedOutput()
   299  	if err != nil {
   300  		if testenv.Builder() == "linux-amd64-alpine" {
   301  			// See Issue 18243 and Issue 19938.
   302  			t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
   303  		}
   304  		t.Fatalf("%s\n\n%v", got, err)
   305  	}
   306  	fn := strings.TrimSpace(string(got))
   307  	defer os.Remove(fn)
   308  
   309  	for try := 0; try < 2; try++ {
   310  		cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-tagignore=ignore", "-traces"))
   311  		// Check that pprof works both with and without explicit executable on command line.
   312  		if try == 0 {
   313  			cmd.Args = append(cmd.Args, exe, fn)
   314  		} else {
   315  			cmd.Args = append(cmd.Args, fn)
   316  		}
   317  
   318  		found := false
   319  		for i, e := range cmd.Env {
   320  			if strings.HasPrefix(e, "PPROF_TMPDIR=") {
   321  				cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
   322  				found = true
   323  				break
   324  			}
   325  		}
   326  		if !found {
   327  			cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   328  		}
   329  
   330  		out, err := cmd.CombinedOutput()
   331  		t.Logf("%s:\n%s", cmd.Args, out)
   332  		if err != nil {
   333  			t.Error(err)
   334  			continue
   335  		}
   336  
   337  		trace := findTrace(string(out), top)
   338  		if len(trace) == 0 {
   339  			t.Errorf("%s traceback missing.", top)
   340  			continue
   341  		}
   342  		if trace[len(trace)-1] != bottom {
   343  			t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
   344  		}
   345  	}
   346  }
   347  
   348  func TestCgoPprof(t *testing.T) {
   349  	testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
   350  }
   351  
   352  func TestCgoPprofPIE(t *testing.T) {
   353  	testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
   354  }
   355  
   356  func TestCgoPprofThread(t *testing.T) {
   357  	testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
   358  }
   359  
   360  func TestCgoPprofThreadNoTraceback(t *testing.T) {
   361  	testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
   362  }
   363  
   364  func TestRaceProf(t *testing.T) {
   365  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   366  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   367  	}
   368  
   369  	testenv.MustHaveGoRun(t)
   370  
   371  	// This test requires building various packages with -race, so
   372  	// it's somewhat slow.
   373  	if testing.Short() {
   374  		t.Skip("skipping test in -short mode")
   375  	}
   376  
   377  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   378  	if err != nil {
   379  		t.Fatal(err)
   380  	}
   381  
   382  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
   383  	if err != nil {
   384  		t.Fatal(err)
   385  	}
   386  	want := "OK\n"
   387  	if string(got) != want {
   388  		t.Errorf("expected %q got %s", want, got)
   389  	}
   390  }
   391  
   392  func TestRaceSignal(t *testing.T) {
   393  	t.Parallel()
   394  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   395  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   396  	}
   397  
   398  	testenv.MustHaveGoRun(t)
   399  
   400  	// This test requires building various packages with -race, so
   401  	// it's somewhat slow.
   402  	if testing.Short() {
   403  		t.Skip("skipping test in -short mode")
   404  	}
   405  
   406  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   407  	if err != nil {
   408  		t.Fatal(err)
   409  	}
   410  
   411  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
   412  	if err != nil {
   413  		t.Logf("%s\n", got)
   414  		t.Fatal(err)
   415  	}
   416  	want := "OK\n"
   417  	if string(got) != want {
   418  		t.Errorf("expected %q got %s", want, got)
   419  	}
   420  }
   421  
   422  func TestCgoNumGoroutine(t *testing.T) {
   423  	switch runtime.GOOS {
   424  	case "windows", "plan9":
   425  		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
   426  	}
   427  	t.Parallel()
   428  	got := runTestProg(t, "testprogcgo", "NumGoroutine")
   429  	want := "OK\n"
   430  	if got != want {
   431  		t.Errorf("expected %q got %v", want, got)
   432  	}
   433  }
   434  
   435  func TestCatchPanic(t *testing.T) {
   436  	t.Parallel()
   437  	switch runtime.GOOS {
   438  	case "plan9", "windows":
   439  		t.Skipf("no signals on %s", runtime.GOOS)
   440  	case "darwin":
   441  		if runtime.GOARCH == "amd64" {
   442  			t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
   443  		}
   444  	}
   445  
   446  	testenv.MustHaveGoRun(t)
   447  
   448  	exe, err := buildTestProg(t, "testprogcgo")
   449  	if err != nil {
   450  		t.Fatal(err)
   451  	}
   452  
   453  	for _, early := range []bool{true, false} {
   454  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
   455  		// Make sure a panic results in a crash.
   456  		cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
   457  		if early {
   458  			// Tell testprogcgo to install an early signal handler for SIGABRT
   459  			cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
   460  		}
   461  		if out, err := cmd.CombinedOutput(); err != nil {
   462  			t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
   463  		}
   464  	}
   465  }
   466  
   467  func TestCgoLockOSThreadExit(t *testing.T) {
   468  	switch runtime.GOOS {
   469  	case "plan9", "windows":
   470  		t.Skipf("no pthreads on %s", runtime.GOOS)
   471  	}
   472  	t.Parallel()
   473  	testLockOSThreadExit(t, "testprogcgo")
   474  }
   475  
   476  func TestWindowsStackMemoryCgo(t *testing.T) {
   477  	if runtime.GOOS != "windows" {
   478  		t.Skip("skipping windows specific test")
   479  	}
   480  	testenv.SkipFlaky(t, 22575)
   481  	o := runTestProg(t, "testprogcgo", "StackMemory")
   482  	stackUsage, err := strconv.Atoi(o)
   483  	if err != nil {
   484  		t.Fatalf("Failed to read stack usage: %v", err)
   485  	}
   486  	if expected, got := 100<<10, stackUsage; got > expected {
   487  		t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
   488  	}
   489  }
   490  
   491  func TestSigStackSwapping(t *testing.T) {
   492  	switch runtime.GOOS {
   493  	case "plan9", "windows":
   494  		t.Skipf("no sigaltstack on %s", runtime.GOOS)
   495  	}
   496  	t.Parallel()
   497  	got := runTestProg(t, "testprogcgo", "SigStack")
   498  	want := "OK\n"
   499  	if got != want {
   500  		t.Errorf("expected %q got %v", want, got)
   501  	}
   502  }
   503  
   504  func TestCgoTracebackSigpanic(t *testing.T) {
   505  	// Test unwinding over a sigpanic in C code without a C
   506  	// symbolizer. See issue #23576.
   507  	if runtime.GOOS == "windows" {
   508  		// On Windows if we get an exception in C code, we let
   509  		// the Windows exception handler unwind it, rather
   510  		// than injecting a sigpanic.
   511  		t.Skip("no sigpanic in C on windows")
   512  	}
   513  	t.Parallel()
   514  	got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
   515  	t.Log(got)
   516  	want := "runtime.sigpanic"
   517  	if !strings.Contains(got, want) {
   518  		t.Errorf("did not see %q in output", want)
   519  	}
   520  	// No runtime errors like "runtime: unexpected return pc".
   521  	nowant := "runtime: "
   522  	if strings.Contains(got, nowant) {
   523  		t.Errorf("unexpectedly saw %q in output", nowant)
   524  	}
   525  }
   526  
   527  func TestCgoPanicCallback(t *testing.T) {
   528  	t.Parallel()
   529  	got := runTestProg(t, "testprogcgo", "PanicCallback")
   530  	t.Log(got)
   531  	want := "panic: runtime error: invalid memory address or nil pointer dereference"
   532  	if !strings.Contains(got, want) {
   533  		t.Errorf("did not see %q in output", want)
   534  	}
   535  	want = "panic_callback"
   536  	if !strings.Contains(got, want) {
   537  		t.Errorf("did not see %q in output", want)
   538  	}
   539  	want = "PanicCallback"
   540  	if !strings.Contains(got, want) {
   541  		t.Errorf("did not see %q in output", want)
   542  	}
   543  	// No runtime errors like "runtime: unexpected return pc".
   544  	nowant := "runtime: "
   545  	if strings.Contains(got, nowant) {
   546  		t.Errorf("did not see %q in output", want)
   547  	}
   548  }
   549  
   550  // Test that C code called via cgo can use large Windows thread stacks
   551  // and call back in to Go without crashing. See issue #20975.
   552  //
   553  // See also TestBigStackCallbackSyscall.
   554  func TestBigStackCallbackCgo(t *testing.T) {
   555  	if runtime.GOOS != "windows" {
   556  		t.Skip("skipping windows specific test")
   557  	}
   558  	t.Parallel()
   559  	got := runTestProg(t, "testprogcgo", "BigStack")
   560  	want := "OK\n"
   561  	if got != want {
   562  		t.Errorf("expected %q got %v", want, got)
   563  	}
   564  }
   565  
   566  func nextTrace(lines []string) ([]string, []string) {
   567  	var trace []string
   568  	for n, line := range lines {
   569  		if strings.HasPrefix(line, "---") {
   570  			return trace, lines[n+1:]
   571  		}
   572  		fields := strings.Fields(strings.TrimSpace(line))
   573  		if len(fields) == 0 {
   574  			continue
   575  		}
   576  		// Last field contains the function name.
   577  		trace = append(trace, fields[len(fields)-1])
   578  	}
   579  	return nil, nil
   580  }
   581  
   582  func findTrace(text, top string) []string {
   583  	lines := strings.Split(text, "\n")
   584  	_, lines = nextTrace(lines) // Skip the header.
   585  	for len(lines) > 0 {
   586  		var t []string
   587  		t, lines = nextTrace(lines)
   588  		if len(t) == 0 {
   589  			continue
   590  		}
   591  		if t[0] == top {
   592  			return t
   593  		}
   594  	}
   595  	return nil
   596  }
   597  
   598  func TestSegv(t *testing.T) {
   599  	switch runtime.GOOS {
   600  	case "plan9", "windows":
   601  		t.Skipf("no signals on %s", runtime.GOOS)
   602  	}
   603  
   604  	for _, test := range []string{"Segv", "SegvInCgo"} {
   605  		test := test
   606  		t.Run(test, func(t *testing.T) {
   607  			t.Parallel()
   608  			got := runTestProg(t, "testprogcgo", test)
   609  			t.Log(got)
   610  			want := "SIGSEGV"
   611  			if !strings.Contains(got, want) {
   612  				if runtime.GOOS == "darwin" && runtime.GOARCH == "amd64" && strings.Contains(got, "fatal: morestack on g0") {
   613  					testenv.SkipFlaky(t, 39457)
   614  				}
   615  				t.Errorf("did not see %q in output", want)
   616  			}
   617  
   618  			// No runtime errors like "runtime: unknown pc".
   619  			switch runtime.GOOS {
   620  			case "darwin", "illumos", "solaris":
   621  				// Runtime sometimes throws when generating the traceback.
   622  				testenv.SkipFlaky(t, 49182)
   623  			case "linux":
   624  				if runtime.GOARCH == "386" {
   625  					// Runtime throws when generating a traceback from
   626  					// a VDSO call via asmcgocall.
   627  					testenv.SkipFlaky(t, 50504)
   628  				}
   629  			}
   630  			if test == "SegvInCgo" && strings.Contains(got, "runtime: unknown pc") {
   631  				testenv.SkipFlaky(t, 50979)
   632  			}
   633  
   634  			nowant := "runtime: "
   635  			if strings.Contains(got, nowant) {
   636  				t.Errorf("unexpectedly saw %q in output", nowant)
   637  			}
   638  		})
   639  	}
   640  }
   641  
   642  func TestAbortInCgo(t *testing.T) {
   643  	switch runtime.GOOS {
   644  	case "plan9", "windows":
   645  		// N.B. On Windows, C abort() causes the program to exit
   646  		// without going through the runtime at all.
   647  		t.Skipf("no signals on %s", runtime.GOOS)
   648  	}
   649  
   650  	t.Parallel()
   651  	got := runTestProg(t, "testprogcgo", "Abort")
   652  	t.Log(got)
   653  	want := "SIGABRT"
   654  	if !strings.Contains(got, want) {
   655  		t.Errorf("did not see %q in output", want)
   656  	}
   657  	// No runtime errors like "runtime: unknown pc".
   658  	nowant := "runtime: "
   659  	if strings.Contains(got, nowant) {
   660  		t.Errorf("did not see %q in output", want)
   661  	}
   662  }
   663  
   664  // TestEINTR tests that we handle EINTR correctly.
   665  // See issue #20400 and friends.
   666  func TestEINTR(t *testing.T) {
   667  	switch runtime.GOOS {
   668  	case "plan9", "windows":
   669  		t.Skipf("no EINTR on %s", runtime.GOOS)
   670  	case "linux":
   671  		if runtime.GOARCH == "386" {
   672  			// On linux-386 the Go signal handler sets
   673  			// a restorer function that is not preserved
   674  			// by the C sigaction call in the test,
   675  			// causing the signal handler to crash when
   676  			// returning the normal code. The test is not
   677  			// architecture-specific, so just skip on 386
   678  			// rather than doing a complicated workaround.
   679  			t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
   680  		}
   681  	}
   682  
   683  	t.Parallel()
   684  	output := runTestProg(t, "testprogcgo", "EINTR")
   685  	want := "OK\n"
   686  	if output != want {
   687  		t.Fatalf("want %s, got %s\n", want, output)
   688  	}
   689  }
   690  
   691  // Issue #42207.
   692  func TestNeedmDeadlock(t *testing.T) {
   693  	switch runtime.GOOS {
   694  	case "plan9", "windows":
   695  		t.Skipf("no signals on %s", runtime.GOOS)
   696  	}
   697  	output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
   698  	want := "OK\n"
   699  	if output != want {
   700  		t.Fatalf("want %s, got %s\n", want, output)
   701  	}
   702  }
   703  
   704  func TestCgoTracebackGoroutineProfile(t *testing.T) {
   705  	output := runTestProg(t, "testprogcgo", "GoroutineProfile")
   706  	want := "OK\n"
   707  	if output != want {
   708  		t.Fatalf("want %s, got %s\n", want, output)
   709  	}
   710  }
   711  

View as plain text