github.com/s1s1ty/go@v0.0.0-20180207192209-104445e3140f/src/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  	case "darwin":
    93  		if runtime.GOARCH != "arm" && runtime.GOARCH != "arm64" {
    94  			// static constructor needs external linking, but we don't support
    95  			// external linking on OS X 10.6.
    96  			out, err := exec.Command("uname", "-r").Output()
    97  			if err != nil {
    98  				t.Fatalf("uname -r failed: %v", err)
    99  			}
   100  			// OS X 10.6 == Darwin 10.x
   101  			if strings.HasPrefix(string(out), "10.") {
   102  				t.Skipf("no external linking on OS X 10.6")
   103  			}
   104  		}
   105  	}
   106  	if runtime.GOARCH == "ppc64" {
   107  		// TODO(austin) External linking not implemented on
   108  		// ppc64 (issue #8912)
   109  		t.Skipf("no external linking on ppc64")
   110  	}
   111  
   112  	exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
   113  	if err != nil {
   114  		t.Fatal(err)
   115  	}
   116  
   117  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
   118  	if err != nil {
   119  		t.Fatalf("exit status: %v\n%s", err, got)
   120  	}
   121  
   122  	if want := "OK\n"; string(got) != want {
   123  		t.Fatalf("expected %q, but got:\n%s", want, got)
   124  	}
   125  }
   126  
   127  func TestCgoExternalThreadSignal(t *testing.T) {
   128  	t.Parallel()
   129  	// issue 10139
   130  	switch runtime.GOOS {
   131  	case "plan9", "windows":
   132  		t.Skipf("no pthreads on %s", runtime.GOOS)
   133  	}
   134  
   135  	exe, err := buildTestProg(t, "testprogcgo", "-tags=threadprof")
   136  	if err != nil {
   137  		t.Fatal(err)
   138  	}
   139  
   140  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoExternalThreadSIGPROF")).CombinedOutput()
   141  	if err != nil {
   142  		t.Fatalf("exit status: %v\n%s", err, got)
   143  	}
   144  
   145  	want := []byte("OK\n")
   146  	if !bytes.Equal(got, want) {
   147  		t.Fatalf("expected %q, but got:\n%s", want, got)
   148  	}
   149  }
   150  
   151  func TestCgoDLLImports(t *testing.T) {
   152  	// test issue 9356
   153  	if runtime.GOOS != "windows" {
   154  		t.Skip("skipping windows specific test")
   155  	}
   156  	got := runTestProg(t, "testprogcgo", "CgoDLLImportsMain")
   157  	want := "OK\n"
   158  	if got != want {
   159  		t.Fatalf("expected %q, but got %v", want, got)
   160  	}
   161  }
   162  
   163  func TestCgoExecSignalMask(t *testing.T) {
   164  	t.Parallel()
   165  	// Test issue 13164.
   166  	switch runtime.GOOS {
   167  	case "windows", "plan9":
   168  		t.Skipf("skipping signal mask test on %s", runtime.GOOS)
   169  	}
   170  	got := runTestProg(t, "testprogcgo", "CgoExecSignalMask")
   171  	want := "OK\n"
   172  	if got != want {
   173  		t.Errorf("expected %q, got %v", want, got)
   174  	}
   175  }
   176  
   177  func TestEnsureDropM(t *testing.T) {
   178  	t.Parallel()
   179  	// Test for issue 13881.
   180  	switch runtime.GOOS {
   181  	case "windows", "plan9":
   182  		t.Skipf("skipping dropm test on %s", runtime.GOOS)
   183  	}
   184  	got := runTestProg(t, "testprogcgo", "EnsureDropM")
   185  	want := "OK\n"
   186  	if got != want {
   187  		t.Errorf("expected %q, got %v", want, got)
   188  	}
   189  }
   190  
   191  // Test for issue 14387.
   192  // Test that the program that doesn't need any cgo pointer checking
   193  // takes about the same amount of time with it as without it.
   194  func TestCgoCheckBytes(t *testing.T) {
   195  	t.Parallel()
   196  	// Make sure we don't count the build time as part of the run time.
   197  	testenv.MustHaveGoBuild(t)
   198  	exe, err := buildTestProg(t, "testprogcgo")
   199  	if err != nil {
   200  		t.Fatal(err)
   201  	}
   202  
   203  	// Try it 10 times to avoid flakiness.
   204  	const tries = 10
   205  	var tot1, tot2 time.Duration
   206  	for i := 0; i < tries; i++ {
   207  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
   208  		cmd.Env = append(cmd.Env, "GODEBUG=cgocheck=0", fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
   209  
   210  		start := time.Now()
   211  		cmd.Run()
   212  		d1 := time.Since(start)
   213  
   214  		cmd = testenv.CleanCmdEnv(exec.Command(exe, "CgoCheckBytes"))
   215  		cmd.Env = append(cmd.Env, fmt.Sprintf("GO_CGOCHECKBYTES_TRY=%d", i))
   216  
   217  		start = time.Now()
   218  		cmd.Run()
   219  		d2 := time.Since(start)
   220  
   221  		if d1*20 > d2 {
   222  			// The slow version (d2) was less than 20 times
   223  			// slower than the fast version (d1), so OK.
   224  			return
   225  		}
   226  
   227  		tot1 += d1
   228  		tot2 += d2
   229  	}
   230  
   231  	t.Errorf("cgo check too slow: got %v, expected at most %v", tot2/tries, (tot1/tries)*20)
   232  }
   233  
   234  func TestCgoPanicDeadlock(t *testing.T) {
   235  	t.Parallel()
   236  	// test issue 14432
   237  	got := runTestProg(t, "testprogcgo", "CgoPanicDeadlock")
   238  	want := "panic: cgo error\n\n"
   239  	if !strings.HasPrefix(got, want) {
   240  		t.Fatalf("output does not start with %q:\n%s", want, got)
   241  	}
   242  }
   243  
   244  func TestCgoCCodeSIGPROF(t *testing.T) {
   245  	t.Parallel()
   246  	got := runTestProg(t, "testprogcgo", "CgoCCodeSIGPROF")
   247  	want := "OK\n"
   248  	if got != want {
   249  		t.Errorf("expected %q got %v", want, got)
   250  	}
   251  }
   252  
   253  func TestCgoCrashTraceback(t *testing.T) {
   254  	t.Parallel()
   255  	if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
   256  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   257  	}
   258  	got := runTestProg(t, "testprogcgo", "CrashTraceback")
   259  	for i := 1; i <= 3; i++ {
   260  		if !strings.Contains(got, fmt.Sprintf("cgo symbolizer:%d", i)) {
   261  			t.Errorf("missing cgo symbolizer:%d", i)
   262  		}
   263  	}
   264  }
   265  
   266  func TestCgoTracebackContext(t *testing.T) {
   267  	t.Parallel()
   268  	got := runTestProg(t, "testprogcgo", "TracebackContext")
   269  	want := "OK\n"
   270  	if got != want {
   271  		t.Errorf("expected %q got %v", want, got)
   272  	}
   273  }
   274  
   275  func testCgoPprof(t *testing.T, buildArg, runArg string) {
   276  	t.Parallel()
   277  	if runtime.GOOS != "linux" || (runtime.GOARCH != "amd64" && runtime.GOARCH != "ppc64le") {
   278  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   279  	}
   280  	testenv.MustHaveGoRun(t)
   281  
   282  	exe, err := buildTestProg(t, "testprogcgo", buildArg)
   283  	if err != nil {
   284  		t.Fatal(err)
   285  	}
   286  
   287  	got, err := testenv.CleanCmdEnv(exec.Command(exe, runArg)).CombinedOutput()
   288  	if err != nil {
   289  		if testenv.Builder() == "linux-amd64-alpine" {
   290  			// See Issue 18243 and Issue 19938.
   291  			t.Skipf("Skipping failing test on Alpine (golang.org/issue/18243). Ignoring error: %v", err)
   292  		}
   293  		t.Fatal(err)
   294  	}
   295  	fn := strings.TrimSpace(string(got))
   296  	defer os.Remove(fn)
   297  
   298  	for try := 0; try < 2; try++ {
   299  		cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1"))
   300  		// Check that pprof works both with and without explicit executable on command line.
   301  		if try == 0 {
   302  			cmd.Args = append(cmd.Args, exe, fn)
   303  		} else {
   304  			cmd.Args = append(cmd.Args, fn)
   305  		}
   306  
   307  		found := false
   308  		for i, e := range cmd.Env {
   309  			if strings.HasPrefix(e, "PPROF_TMPDIR=") {
   310  				cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
   311  				found = true
   312  				break
   313  			}
   314  		}
   315  		if !found {
   316  			cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   317  		}
   318  
   319  		top, err := cmd.CombinedOutput()
   320  		t.Logf("%s:\n%s", cmd.Args, top)
   321  		if err != nil {
   322  			t.Error(err)
   323  		} else if !bytes.Contains(top, []byte("cpuHog")) {
   324  			t.Error("missing cpuHog in pprof output")
   325  		}
   326  	}
   327  }
   328  
   329  func TestCgoPprof(t *testing.T) {
   330  	testCgoPprof(t, "", "CgoPprof")
   331  }
   332  
   333  func TestCgoPprofPIE(t *testing.T) {
   334  	testCgoPprof(t, "-buildmode=pie", "CgoPprof")
   335  }
   336  
   337  func TestCgoPprofThread(t *testing.T) {
   338  	testCgoPprof(t, "", "CgoPprofThread")
   339  }
   340  
   341  func TestCgoPprofThreadNoTraceback(t *testing.T) {
   342  	testCgoPprof(t, "", "CgoPprofThreadNoTraceback")
   343  }
   344  
   345  func TestRaceProf(t *testing.T) {
   346  	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
   347  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   348  	}
   349  
   350  	testenv.MustHaveGoRun(t)
   351  
   352  	// This test requires building various packages with -race, so
   353  	// it's somewhat slow.
   354  	if testing.Short() {
   355  		t.Skip("skipping test in -short mode")
   356  	}
   357  
   358  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   359  	if err != nil {
   360  		t.Fatal(err)
   361  	}
   362  
   363  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
   364  	if err != nil {
   365  		t.Fatal(err)
   366  	}
   367  	want := "OK\n"
   368  	if string(got) != want {
   369  		t.Errorf("expected %q got %s", want, got)
   370  	}
   371  }
   372  
   373  func TestRaceSignal(t *testing.T) {
   374  	t.Parallel()
   375  	if runtime.GOOS != "linux" || runtime.GOARCH != "amd64" {
   376  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   377  	}
   378  
   379  	testenv.MustHaveGoRun(t)
   380  
   381  	// This test requires building various packages with -race, so
   382  	// it's somewhat slow.
   383  	if testing.Short() {
   384  		t.Skip("skipping test in -short mode")
   385  	}
   386  
   387  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   388  	if err != nil {
   389  		t.Fatal(err)
   390  	}
   391  
   392  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
   393  	if err != nil {
   394  		t.Logf("%s\n", got)
   395  		t.Fatal(err)
   396  	}
   397  	want := "OK\n"
   398  	if string(got) != want {
   399  		t.Errorf("expected %q got %s", want, got)
   400  	}
   401  }
   402  
   403  func TestCgoNumGoroutine(t *testing.T) {
   404  	switch runtime.GOOS {
   405  	case "windows", "plan9":
   406  		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
   407  	}
   408  	t.Parallel()
   409  	got := runTestProg(t, "testprogcgo", "NumGoroutine")
   410  	want := "OK\n"
   411  	if got != want {
   412  		t.Errorf("expected %q got %v", want, got)
   413  	}
   414  }
   415  
   416  func TestCatchPanic(t *testing.T) {
   417  	t.Parallel()
   418  	switch runtime.GOOS {
   419  	case "plan9", "windows":
   420  		t.Skipf("no signals on %s", runtime.GOOS)
   421  	case "darwin":
   422  		if runtime.GOARCH == "amd64" {
   423  			t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
   424  		}
   425  	}
   426  
   427  	testenv.MustHaveGoRun(t)
   428  
   429  	exe, err := buildTestProg(t, "testprogcgo")
   430  	if err != nil {
   431  		t.Fatal(err)
   432  	}
   433  
   434  	for _, early := range []bool{true, false} {
   435  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
   436  		// Make sure a panic results in a crash.
   437  		cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
   438  		if early {
   439  			// Tell testprogcgo to install an early signal handler for SIGABRT
   440  			cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
   441  		}
   442  		if out, err := cmd.CombinedOutput(); err != nil {
   443  			t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
   444  		}
   445  	}
   446  }
   447  
   448  func TestCgoLockOSThreadExit(t *testing.T) {
   449  	switch runtime.GOOS {
   450  	case "plan9", "windows":
   451  		t.Skipf("no pthreads on %s", runtime.GOOS)
   452  	}
   453  	t.Parallel()
   454  	testLockOSThreadExit(t, "testprogcgo")
   455  }
   456  
   457  func TestWindowsStackMemoryCgo(t *testing.T) {
   458  	if runtime.GOOS != "windows" {
   459  		t.Skip("skipping windows specific test")
   460  	}
   461  	testenv.SkipFlaky(t, 22575)
   462  	o := runTestProg(t, "testprogcgo", "StackMemory")
   463  	stackUsage, err := strconv.Atoi(o)
   464  	if err != nil {
   465  		t.Fatalf("Failed to read stack usage: %v", err)
   466  	}
   467  	if expected, got := 100<<10, stackUsage; got > expected {
   468  		t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
   469  	}
   470  }
   471  
   472  func TestSigStackSwapping(t *testing.T) {
   473  	switch runtime.GOOS {
   474  	case "plan9", "windows":
   475  		t.Skipf("no sigaltstack on %s", runtime.GOOS)
   476  	}
   477  	t.Parallel()
   478  	got := runTestProg(t, "testprogcgo", "SigStack")
   479  	want := "OK\n"
   480  	if got != want {
   481  		t.Errorf("expected %q got %v", want, got)
   482  	}
   483  }
   484  
   485  func TestCgoTracebackSigpanic(t *testing.T) {
   486  	// Test unwinding over a sigpanic in C code without a C
   487  	// symbolizer. See issue #23576.
   488  	if runtime.GOOS == "windows" {
   489  		// On Windows if we get an exception in C code, we let
   490  		// the Windows exception handler unwind it, rather
   491  		// than injecting a sigpanic.
   492  		t.Skip("no sigpanic in C on windows")
   493  	}
   494  	t.Parallel()
   495  	got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
   496  	want := "runtime.sigpanic"
   497  	if !strings.Contains(got, want) {
   498  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
   499  	}
   500  	nowant := "unexpected return pc"
   501  	if strings.Contains(got, nowant) {
   502  		t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
   503  	}
   504  }