github.com/lzhfromustc/gofuzz@v0.0.0-20211116160056-151b3108bbd1/runtime/crash_cgo_test.go (about)

     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  // +build cgo
     6  
     7  package runtime_test
     8  
     9  import (
    10  	"bytes"
    11  	"fmt"
    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  	got := runTestProg(t, "testprogcgo", "CgoCallbackGC")
    68  	want := "OK\n"
    69  	if got != want {
    70  		t.Fatalf("expected %q, but got:\n%s", want, got)
    71  	}
    72  }
    73  
    74  func TestCgoExternalThreadPanic(t *testing.T) {
    75  	t.Parallel()
    76  	if runtime.GOOS == "plan9" {
    77  		t.Skipf("no pthreads on %s", runtime.GOOS)
    78  	}
    79  	got := runTestProg(t, "testprogcgo", "CgoExternalThreadPanic")
    80  	want := "panic: BOOM"
    81  	if !strings.Contains(got, want) {
    82  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
    83  	}
    84  }
    85  
    86  func TestCgoExternalThreadSIGPROF(t *testing.T) {
    87  	t.Parallel()
    88  	// issue 9456.
    89  	switch runtime.GOOS {
    90  	case "plan9", "windows":
    91  		t.Skipf("no pthreads on %s", runtime.GOOS)
    92  	}
    93  	if runtime.GOARCH == "ppc64" && runtime.GOOS == "linux" {
    94  		// TODO(austin) External linking not implemented on
    95  		// linux/ppc64 (issue #8912)
    96  		t.Skipf("no external linking on ppc64")
    97  	}
    98  
    99  	exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
   100  	if err != nil {
   101  		t.Fatal(err)
   102  	}
   103  
   104  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
   105  	if err != nil {
   106  		t.Fatalf("exit status: %v\n%s", err, got)
   107  	}
   108  
   109  	if want := "OK\n"; string(got) != want {
   110  		t.Fatalf("expected %q, but got:\n%s", want, got)
   111  	}
   112  }
   113  
   114  func TestCgoExternalThreadSignal(t *testing.T) {
   115  	t.Parallel()
   116  	// issue 10139
   117  	switch runtime.GOOS {
   118  	case "plan9", "windows":
   119  		t.Skipf("no pthreads on %s", runtime.GOOS)
   120  	}
   121  
   122  	exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
   123  	if err != nil {
   124  		t.Fatal(err)
   125  	}
   126  
   127  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
   128  	if err != nil {
   129  		t.Fatalf("exit status: %v\n%s", err, got)
   130  	}
   131  
   132  	want := []byte("OK\n")
   133  	if !bytes.Equal(got, want) {
   134  		t.Fatalf("expected %q, but got:\n%s", want, got)
   135  	}
   136  }
   137  
   138  func TestCgoDLLImports(t *testing.T) {
   139  	// test issue 9356
   140  	if runtime.GOOS != "windows" {
   141  		t.Skip("skipping windows specific test")
   142  	}
   143  	got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
   144  	want := "OK\n"
   145  	if got != want {
   146  		t.Fatalf("expected %q, but got %v", want, got)
   147  	}
   148  }
   149  
   150  func TestCgoExecSignalMask(t *testing.T) {
   151  	t.Parallel()
   152  	// Test issue 13164.
   153  	switch runtime.GOOS {
   154  	case "windows", "plan9":
   155  		t.Skipf("skipping signal mask test on %s", runtime.GOOS)
   156  	}
   157  	got := runTestProg(t, "testprogcgo", "CgoExecSignalMask", "GOTRACEBACK=system")
   158  	want := "OK\n"
   159  	if got != want {
   160  		t.Errorf("expected %q, got %v", want, got)
   161  	}
   162  }
   163  
   164  func TestEnsureDropM(t *testing.T) {
   165  	t.Parallel()
   166  	// Test for issue 13881.
   167  	switch runtime.GOOS {
   168  	case "windows", "plan9":
   169  		t.Skipf("skipping dropm test on %s", runtime.GOOS)
   170  	}
   171  	got := runTestProg(t, "testprogcgo", "EnsureDropM")
   172  	want := "OK\n"
   173  	if got != want {
   174  		t.Errorf("expected %q, got %v", want, got)
   175  	}
   176  }
   177  
   178  // Test for issue 14387.
   179  // Test that the program that doesn't need any cgo pointer checking
   180  // takes about the same amount of time with it as without it.
   181  func TestCgoCheckBytes(t *testing.T) {
   182  	t.Parallel()
   183  	// Make sure we don't count the build time as part of the run time.
   184  	testenv.MustHaveGoBuild(t)
   185  	exe, err := buildTestProg(t, "testprogcgo")
   186  	if err != nil {
   187  		t.Fatal(err)
   188  	}
   189  
   190  	// Try it 10 times to avoid flakiness.
   191  	const tries = 10
   192  	var tot1, tot2 time.Duration
   193  	for i := 0; i < tries; i++ {
   194  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
   195  		cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
   196  
   197  		start := time.Now()
   198  		cmd.Run()
   199  		d1 := time.Since(start)
   200  
   201  		cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
   202  		cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
   203  
   204  		start = time.Now()
   205  		cmd.Run()
   206  		d2 := time.Since(start)
   207  
   208  		if d1*20 > d2 {
   209  			// The slow version (d2) was less than 20 times
   210  			// slower than the fast version (d1), so OK.
   211  			return
   212  		}
   213  
   214  		tot1 += d1
   215  		tot2 += d2
   216  	}
   217  
   218  	t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
   219  }
   220  
   221  func TestCgoPanicDeadlock(t *testing.T) {
   222  	t.Parallel()
   223  	// test issue 14432
   224  	got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
   225  	want := "panic: cgo error\n\n"
   226  	if !strings.HasPrefix(got, want) {
   227  		t.Fatalf("output does not start with %q:\n%s", want, got)
   228  	}
   229  }
   230  
   231  func TestCgoCCodeSIGPROF(t *testing.T) {
   232  	t.Parallel()
   233  	got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
   234  	want := "OK\n"
   235  	if got != want {
   236  		t.Errorf("expected %q got %v", want, got)
   237  	}
   238  }
   239  
   240  func TestCgoCrashTraceback(t *testing.T) {
   241  	t.Parallel()
   242  	switch platform := runtime.GOOS + "/" + runtime.GOARCH; platform {
   243  	case "darwin/amd64":
   244  	case "linux/amd64":
   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/ppc64le":
   263  	default:
   264  		t.Skipf("not yet supported on %s", platform)
   265  	}
   266  	got := runTestProg(t, "testprogcgo", "CrashTracebackGo")
   267  	for i := 1; i <= 3; i++ {
   268  		want := fmt.Sprintf("main.h%d", i)
   269  		if !strings.Contains(got, want) {
   270  			t.Errorf("missing %s", want)
   271  		}
   272  	}
   273  }
   274  
   275  func TestCgoTracebackContext(t *testing.T) {
   276  	t.Parallel()
   277  	got := runTestProg(t, "testprogcgo", "TracebackContext")
   278  	want := "OK\n"
   279  	if got != want {
   280  		t.Errorf("expected %q got %v", want, got)
   281  	}
   282  }
   283  
   284  func testCgoPprof(t *testing.T, buildArg, runArg, top, bottom string) {
   285  	t.Parallel()
   286  	if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
   287  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   288  	}
   289  	testenv.MustHaveGoRun(t)
   290  
   291  	exe, err := buildTestProg(t, "testprogcgo", buildArg)
   292  	if err != nil {
   293  		t.Fatal(err)
   294  	}
   295  
   296  	// pprofCgoTraceback is called whenever CGO code is executing and a signal
   297  	// is received. Disable signal preemption to increase the likelihood at
   298  	// least one SIGPROF signal fired to capture a sample. See issue #37201.
   299  	cmd := testenv.CleanCmdEnv(exec.Command(exe, runArg))
   300  	cmd.Env = append(cmd.Env, "GODEBUG=asyncpreemptoff=1")
   301  
   302  	got, err := cmd.CombinedOutput()
   303  	if err != nil {
   304  		if testenv.Builder() == "linux-amd64-alpine" {
   305  			// See Issue 18243 and Issue 19938.
   306  			t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
   307  		}
   308  		t.Fatalf("%s\n\n%v", got, err)
   309  	}
   310  	fn := strings.TrimSpace(string(got))
   311  	defer os.Remove(fn)
   312  
   313  	for try := 0; try < 2; try++ {
   314  		cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-traces"))
   315  		// Check that pprof works both with and without explicit executable on command line.
   316  		if try == 0 {
   317  			cmd.Args = append(cmd.Args, exe, fn)
   318  		} else {
   319  			cmd.Args = append(cmd.Args, fn)
   320  		}
   321  
   322  		found := false
   323  		for i, e := range cmd.Env {
   324  			if strings.HasPrefix(e, "PPROF_TMPDIR=") {
   325  				cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
   326  				found = true
   327  				break
   328  			}
   329  		}
   330  		if !found {
   331  			cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   332  		}
   333  
   334  		out, err := cmd.CombinedOutput()
   335  		t.Logf("%s:\n%s", cmd.Args, out)
   336  		if err != nil {
   337  			t.Error(err)
   338  			continue
   339  		}
   340  
   341  		trace := findTrace(string(out), top)
   342  		if len(trace) == 0 {
   343  			t.Errorf("%s traceback missing.", top)
   344  			continue
   345  		}
   346  		if trace[len(trace)-1] != bottom {
   347  			t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
   348  		}
   349  	}
   350  }
   351  
   352  func TestCgoPprof(t *testing.T) {
   353  	testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
   354  }
   355  
   356  func TestCgoPprofPIE(t *testing.T) {
   357  	testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
   358  }
   359  
   360  func TestCgoPprofThread(t *testing.T) {
   361  	testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
   362  }
   363  
   364  func TestCgoPprofThreadNoTraceback(t *testing.T) {
   365  	testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
   366  }
   367  
   368  func TestRaceProf(t *testing.T) {
   369  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   370  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   371  	}
   372  
   373  	testenv.MustHaveGoRun(t)
   374  
   375  	// This test requires building various packages with -race, so
   376  	// it's somewhat slow.
   377  	if testing.Short() {
   378  		t.Skip("skipping test in -short mode")
   379  	}
   380  
   381  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   382  	if err != nil {
   383  		t.Fatal(err)
   384  	}
   385  
   386  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  	want := "OK\n"
   391  	if string(got) != want {
   392  		t.Errorf("expected %q got %s", want, got)
   393  	}
   394  }
   395  
   396  func TestRaceSignal(t *testing.T) {
   397  	t.Parallel()
   398  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   399  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   400  	}
   401  
   402  	testenv.MustHaveGoRun(t)
   403  
   404  	// This test requires building various packages with -race, so
   405  	// it's somewhat slow.
   406  	if testing.Short() {
   407  		t.Skip("skipping test in -short mode")
   408  	}
   409  
   410  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   411  	if err != nil {
   412  		t.Fatal(err)
   413  	}
   414  
   415  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
   416  	if err != nil {
   417  		t.Logf("%s\n", got)
   418  		t.Fatal(err)
   419  	}
   420  	want := "OK\n"
   421  	if string(got) != want {
   422  		t.Errorf("expected %q got %s", want, got)
   423  	}
   424  }
   425  
   426  func TestCgoNumGoroutine(t *testing.T) {
   427  	switch runtime.GOOS {
   428  	case "windows", "plan9":
   429  		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
   430  	}
   431  	t.Parallel()
   432  	got := runTestProg(t, "testprogcgo", "NumGoroutine")
   433  	want := "OK\n"
   434  	if got != want {
   435  		t.Errorf("expected %q got %v", want, got)
   436  	}
   437  }
   438  
   439  func TestCatchPanic(t *testing.T) {
   440  	t.Parallel()
   441  	switch runtime.GOOS {
   442  	case "plan9", "windows":
   443  		t.Skipf("no signals on %s", runtime.GOOS)
   444  	case "darwin":
   445  		if runtime.GOARCH == "amd64" {
   446  			t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
   447  		}
   448  	}
   449  
   450  	testenv.MustHaveGoRun(t)
   451  
   452  	exe, err := buildTestProg(t, "testprogcgo")
   453  	if err != nil {
   454  		t.Fatal(err)
   455  	}
   456  
   457  	for _, early := range []bool{true, false} {
   458  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
   459  		// Make sure a panic results in a crash.
   460  		cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
   461  		if early {
   462  			// Tell testprogcgo to install an early signal handler for SIGABRT
   463  			cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
   464  		}
   465  		if out, err := cmd.CombinedOutput(); err != nil {
   466  			t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
   467  		}
   468  	}
   469  }
   470  
   471  func TestCgoLockOSThreadExit(t *testing.T) {
   472  	switch runtime.GOOS {
   473  	case "plan9", "windows":
   474  		t.Skipf("no pthreads on %s", runtime.GOOS)
   475  	}
   476  	t.Parallel()
   477  	testLockOSThreadExit(t, "testprogcgo")
   478  }
   479  
   480  func TestWindowsStackMemoryCgo(t *testing.T) {
   481  	if runtime.GOOS != "windows" {
   482  		t.Skip("skipping windows specific test")
   483  	}
   484  	testenv.SkipFlaky(t, 22575)
   485  	o := runTestProg(t, "testprogcgo", "StackMemory")
   486  	stackUsage, err := strconv.Atoi(o)
   487  	if err != nil {
   488  		t.Fatalf("Failed to read stack usage: %v", err)
   489  	}
   490  	if expected, got := 100<<10, stackUsage; got > expected {
   491  		t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
   492  	}
   493  }
   494  
   495  func TestSigStackSwapping(t *testing.T) {
   496  	switch runtime.GOOS {
   497  	case "plan9", "windows":
   498  		t.Skipf("no sigaltstack on %s", runtime.GOOS)
   499  	}
   500  	t.Parallel()
   501  	got := runTestProg(t, "testprogcgo", "SigStack")
   502  	want := "OK\n"
   503  	if got != want {
   504  		t.Errorf("expected %q got %v", want, got)
   505  	}
   506  }
   507  
   508  func TestCgoTracebackSigpanic(t *testing.T) {
   509  	// Test unwinding over a sigpanic in C code without a C
   510  	// symbolizer. See issue #23576.
   511  	if runtime.GOOS == "windows" {
   512  		// On Windows if we get an exception in C code, we let
   513  		// the Windows exception handler unwind it, rather
   514  		// than injecting a sigpanic.
   515  		t.Skip("no sigpanic in C on windows")
   516  	}
   517  	t.Parallel()
   518  	got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
   519  	want := "runtime.sigpanic"
   520  	if !strings.Contains(got, want) {
   521  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
   522  	}
   523  	nowant := "unexpected return pc"
   524  	if strings.Contains(got, nowant) {
   525  		t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
   526  	}
   527  }
   528  
   529  // Test that C code called via cgo can use large Windows thread stacks
   530  // and call back in to Go without crashing. See issue #20975.
   531  //
   532  // See also TestBigStackCallbackSyscall.
   533  func TestBigStackCallbackCgo(t *testing.T) {
   534  	if runtime.GOOS != "windows" {
   535  		t.Skip("skipping windows specific test")
   536  	}
   537  	t.Parallel()
   538  	got := runTestProg(t, "testprogcgo", "BigStack")
   539  	want := "OK\n"
   540  	if got != want {
   541  		t.Errorf("expected %q got %v", want, got)
   542  	}
   543  }
   544  
   545  func nextTrace(lines []string) ([]string, []string) {
   546  	var trace []string
   547  	for n, line := range lines {
   548  		if strings.HasPrefix(line, "---") {
   549  			return trace, lines[n+1:]
   550  		}
   551  		fields := strings.Fields(strings.TrimSpace(line))
   552  		if len(fields) == 0 {
   553  			continue
   554  		}
   555  		// Last field contains the function name.
   556  		trace = append(trace, fields[len(fields)-1])
   557  	}
   558  	return nil, nil
   559  }
   560  
   561  func findTrace(text, top string) []string {
   562  	lines := strings.Split(text, "\n")
   563  	_, lines = nextTrace(lines) // Skip the header.
   564  	for len(lines) > 0 {
   565  		var t []string
   566  		t, lines = nextTrace(lines)
   567  		if len(t) == 0 {
   568  			continue
   569  		}
   570  		if t[0] == top {
   571  			return t
   572  		}
   573  	}
   574  	return nil
   575  }
   576  
   577  func TestSegv(t *testing.T) {
   578  	switch runtime.GOOS {
   579  	case "plan9", "windows":
   580  		t.Skipf("no signals on %s", runtime.GOOS)
   581  	}
   582  
   583  	for _, test := range []string{"Segv", "SegvInCgo"} {
   584  		t.Run(test, func(t *testing.T) {
   585  			t.Parallel()
   586  			got := runTestProg(t, "testprogcgo", test)
   587  			t.Log(got)
   588  			if !strings.Contains(got, "SIGSEGV") {
   589  				t.Errorf("expected crash from signal")
   590  			}
   591  		})
   592  	}
   593  }
   594  
   595  // TestEINTR tests that we handle EINTR correctly.
   596  // See issue #20400 and friends.
   597  func TestEINTR(t *testing.T) {
   598  	switch runtime.GOOS {
   599  	case "plan9", "windows":
   600  		t.Skipf("no EINTR on %s", runtime.GOOS)
   601  	case "linux":
   602  		if runtime.GOARCH == "386" {
   603  			// On linux-386 the Go signal handler sets
   604  			// a restorer function that is not preserved
   605  			// by the C sigaction call in the test,
   606  			// causing the signal handler to crash when
   607  			// returning the normal code. The test is not
   608  			// architecture-specific, so just skip on 386
   609  			// rather than doing a complicated workaround.
   610  			t.Skip("skipping on linux-386; C sigaction does not preserve Go restorer")
   611  		}
   612  	}
   613  
   614  	t.Parallel()
   615  	output := runTestProg(t, "testprogcgo", "EINTR")
   616  	want := "OK\n"
   617  	if output != want {
   618  		t.Fatalf("want %s, got %s\n", want, output)
   619  	}
   620  }
   621  
   622  // Issue #42207.
   623  func TestNeedmDeadlock(t *testing.T) {
   624  	switch runtime.GOOS {
   625  	case "plan9", "windows":
   626  		t.Skipf("no signals on %s", runtime.GOOS)
   627  	}
   628  	output := runTestProg(t, "testprogcgo", "NeedmDeadlock")
   629  	want := "OK\n"
   630  	if output != want {
   631  		t.Fatalf("want %s, got %s\n", want, output)
   632  	}
   633  }