...
Run Format

Source file src/runtime/crash_cgo_test.go

Documentation: runtime

     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" {
    94  		// TODO(austin) External linking not implemented on
    95  		// 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")
   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 TestCgoTracebackContext(t *testing.T) {
   258  	t.Parallel()
   259  	got := runTestProg(t, "testprogcgo", "TracebackContext")
   260  	want := "OK\n"
   261  	if got != want {
   262  		t.Errorf("expected %q got %v", want, got)
   263  	}
   264  }
   265  
   266  func testCgoPprof(t *testing.T, buildArg, runArg string) {
   267  	t.Parallel()
   268  	if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
   269  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   270  	}
   271  	testenv.MustHaveGoRun(t)
   272  
   273  	exe, err := buildTestProg(t, "testprogcgo", buildArg)
   274  	if err != nil {
   275  		t.Fatal(err)
   276  	}
   277  
   278  	got, err := testenv.CleanCmdEnv(exec.Command(exe, runArg)).CombinedOutput()
   279  	if err != nil {
   280  		if testenv.Builder() == "linux-amd64-alpine" {
   281  			// See Issue 18243 and Issue 19938.
   282  			t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
   283  		}
   284  		t.Fatal(err)
   285  	}
   286  	fn := strings.TrimSpace(string(got))
   287  	defer os.Remove(fn)
   288  
   289  	for try := 0; try < 2; try++ {
   290  		cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1"))
   291  		// Check that pprof works both with and without explicit executable on command line.
   292  		if try == 0 {
   293  			cmd.Args = append(cmd.Args, exe, fn)
   294  		} else {
   295  			cmd.Args = append(cmd.Args, fn)
   296  		}
   297  
   298  		found := false
   299  		for i, e := range cmd.Env {
   300  			if strings.HasPrefix(e, "PPROF_TMPDIR=") {
   301  				cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
   302  				found = true
   303  				break
   304  			}
   305  		}
   306  		if !found {
   307  			cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   308  		}
   309  
   310  		top, err := cmd.CombinedOutput()
   311  		t.Logf("%s:\n%s", cmd.Args, top)
   312  		if err != nil {
   313  			t.Error(err)
   314  		} else if !bytes.Contains(top, []byte("cpuHog")) {
   315  			t.Error("missing cpuHog in pprof output")
   316  		}
   317  	}
   318  }
   319  
   320  func TestCgoPprof(t *testing.T) {
   321  	testCgoPprof(t, "", "CgoPprof")
   322  }
   323  
   324  func TestCgoPprofPIE(t *testing.T) {
   325  	testCgoPprof(t, "-buildmode=pie", "CgoPprof")
   326  }
   327  
   328  func TestCgoPprofThread(t *testing.T) {
   329  	testCgoPprof(t, "", "CgoPprofThread")
   330  }
   331  
   332  func TestCgoPprofThreadNoTraceback(t *testing.T) {
   333  	testCgoPprof(t, "", "CgoPprofThreadNoTraceback")
   334  }
   335  
   336  func TestRaceProf(t *testing.T) {
   337  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   338  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   339  	}
   340  
   341  	testenv.MustHaveGoRun(t)
   342  
   343  	// This test requires building various packages with -race, so
   344  	// it's somewhat slow.
   345  	if testing.Short() {
   346  		t.Skip("skipping test in -short mode")
   347  	}
   348  
   349  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   350  	if err != nil {
   351  		t.Fatal(err)
   352  	}
   353  
   354  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
   355  	if err != nil {
   356  		t.Fatal(err)
   357  	}
   358  	want := "OK\n"
   359  	if string(got) != want {
   360  		t.Errorf("expected %q got %s", want, got)
   361  	}
   362  }
   363  
   364  func TestRaceSignal(t *testing.T) {
   365  	t.Parallel()
   366  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   367  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   368  	}
   369  
   370  	testenv.MustHaveGoRun(t)
   371  
   372  	// This test requires building various packages with -race, so
   373  	// it's somewhat slow.
   374  	if testing.Short() {
   375  		t.Skip("skipping test in -short mode")
   376  	}
   377  
   378  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   379  	if err != nil {
   380  		t.Fatal(err)
   381  	}
   382  
   383  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
   384  	if err != nil {
   385  		t.Logf("%s\n", got)
   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 TestCgoNumGoroutine(t *testing.T) {
   395  	switch runtime.GOOS {
   396  	case "windows", "plan9":
   397  		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
   398  	}
   399  	t.Parallel()
   400  	got := runTestProg(t, "testprogcgo", "NumGoroutine")
   401  	want := "OK\n"
   402  	if got != want {
   403  		t.Errorf("expected %q got %v", want, got)
   404  	}
   405  }
   406  
   407  func TestCatchPanic(t *testing.T) {
   408  	t.Parallel()
   409  	switch runtime.GOOS {
   410  	case "plan9", "windows":
   411  		t.Skipf("no signals on %s", runtime.GOOS)
   412  	case "darwin":
   413  		if runtime.GOARCH == "amd64" {
   414  			t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
   415  		}
   416  	}
   417  
   418  	testenv.MustHaveGoRun(t)
   419  
   420  	exe, err := buildTestProg(t, "testprogcgo")
   421  	if err != nil {
   422  		t.Fatal(err)
   423  	}
   424  
   425  	for _, early := range []bool{true, false} {
   426  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
   427  		// Make sure a panic results in a crash.
   428  		cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
   429  		if early {
   430  			// Tell testprogcgo to install an early signal handler for SIGABRT
   431  			cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
   432  		}
   433  		if out, err := cmd.CombinedOutput(); err != nil {
   434  			t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
   435  		}
   436  	}
   437  }
   438  
   439  func TestCgoLockOSThreadExit(t *testing.T) {
   440  	switch runtime.GOOS {
   441  	case "plan9", "windows":
   442  		t.Skipf("no pthreads on %s", runtime.GOOS)
   443  	}
   444  	t.Parallel()
   445  	testLockOSThreadExit(t, "testprogcgo")
   446  }
   447  
   448  func TestWindowsStackMemoryCgo(t *testing.T) {
   449  	if runtime.GOOS != "windows" {
   450  		t.Skip("skipping windows specific test")
   451  	}
   452  	testenv.SkipFlaky(t, 22575)
   453  	o := runTestProg(t, "testprogcgo", "StackMemory")
   454  	stackUsage, err := strconv.Atoi(o)
   455  	if err != nil {
   456  		t.Fatalf("Failed to read stack usage: %v", err)
   457  	}
   458  	if expected, got := 100<<10, stackUsage; got > expected {
   459  		t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
   460  	}
   461  }
   462  
   463  func TestSigStackSwapping(t *testing.T) {
   464  	switch runtime.GOOS {
   465  	case "plan9", "windows":
   466  		t.Skipf("no sigaltstack on %s", runtime.GOOS)
   467  	}
   468  	t.Parallel()
   469  	got := runTestProg(t, "testprogcgo", "SigStack")
   470  	want := "OK\n"
   471  	if got != want {
   472  		t.Errorf("expected %q got %v", want, got)
   473  	}
   474  }
   475  
   476  func TestCgoTracebackSigpanic(t *testing.T) {
   477  	// Test unwinding over a sigpanic in C code without a C
   478  	// symbolizer. See issue #23576.
   479  	if runtime.GOOS == "windows" {
   480  		// On Windows if we get an exception in C code, we let
   481  		// the Windows exception handler unwind it, rather
   482  		// than injecting a sigpanic.
   483  		t.Skip("no sigpanic in C on windows")
   484  	}
   485  	t.Parallel()
   486  	got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
   487  	want := "runtime.sigpanic"
   488  	if !strings.Contains(got, want) {
   489  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
   490  	}
   491  	nowant := "unexpected return pc"
   492  	if strings.Contains(got, nowant) {
   493  		t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
   494  	}
   495  }
   496  
   497  // Test that C code called via cgo can use large Windows thread stacks
   498  // and call back in to Go without crashing. See issue #20975.
   499  //
   500  // See also TestBigStackCallbackSyscall.
   501  func TestBigStackCallbackCgo(t *testing.T) {
   502  	if runtime.GOOS != "windows" {
   503  		t.Skip("skipping windows specific test")
   504  	}
   505  	t.Parallel()
   506  	got := runTestProg(t, "testprogcgo", "BigStack")
   507  	want := "OK\n"
   508  	if got != want {
   509  		t.Errorf("expected %q got %v", want, got)
   510  	}
   511  }
   512  

View as plain text