github.com/megatontech/mynoteforgo@v0.0.0-20200507084910-5d0c6ea6e890/源码/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" {
    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, top, bottom 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", "-traces"))
   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  		out, err := cmd.CombinedOutput()
   311  		t.Logf("%s:\n%s", cmd.Args, out)
   312  		if err != nil {
   313  			t.Error(err)
   314  			continue
   315  		}
   316  
   317  		trace := findTrace(string(out), top)
   318  		if len(trace) == 0 {
   319  			t.Errorf("%s traceback missing.", top)
   320  			continue
   321  		}
   322  		if trace[len(trace)-1] != bottom {
   323  			t.Errorf("invalid traceback origin: got=%v; want=[%s ... %s]", trace, top, bottom)
   324  		}
   325  	}
   326  }
   327  
   328  func TestCgoPprof(t *testing.T) {
   329  	testCgoPprof(t, "", "CgoPprof", "cpuHog", "runtime.main")
   330  }
   331  
   332  func TestCgoPprofPIE(t *testing.T) {
   333  	testCgoPprof(t, "-buildmode=pie", "CgoPprof", "cpuHog", "runtime.main")
   334  }
   335  
   336  func TestCgoPprofThread(t *testing.T) {
   337  	testCgoPprof(t, "", "CgoPprofThread", "cpuHogThread", "cpuHogThread2")
   338  }
   339  
   340  func TestCgoPprofThreadNoTraceback(t *testing.T) {
   341  	testCgoPprof(t, "", "CgoPprofThreadNoTraceback", "cpuHogThread", "runtime._ExternalCode")
   342  }
   343  
   344  func TestRaceProf(t *testing.T) {
   345  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   346  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   347  	}
   348  
   349  	testenv.MustHaveGoRun(t)
   350  
   351  	// This test requires building various packages with -race, so
   352  	// it's somewhat slow.
   353  	if testing.Short() {
   354  		t.Skip("skipping test in -short mode")
   355  	}
   356  
   357  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   358  	if err != nil {
   359  		t.Fatal(err)
   360  	}
   361  
   362  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceprof")).CombinedOutput()
   363  	if err != nil {
   364  		t.Fatal(err)
   365  	}
   366  	want := "OK\n"
   367  	if string(got) != want {
   368  		t.Errorf("expected %q got %s", want, got)
   369  	}
   370  }
   371  
   372  func TestRaceSignal(t *testing.T) {
   373  	t.Parallel()
   374  	if (runtime.GOOS != "linux" && runtime.GOOS != "freebsd") || runtime.GOARCH != "amd64" {
   375  		t.Skipf("not yet supported on %s/%s", runtime.GOOS, runtime.GOARCH)
   376  	}
   377  
   378  	testenv.MustHaveGoRun(t)
   379  
   380  	// This test requires building various packages with -race, so
   381  	// it's somewhat slow.
   382  	if testing.Short() {
   383  		t.Skip("skipping test in -short mode")
   384  	}
   385  
   386  	exe, err := buildTestProg(t, "testprogcgo", "-race")
   387  	if err != nil {
   388  		t.Fatal(err)
   389  	}
   390  
   391  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "CgoRaceSignal")).CombinedOutput()
   392  	if err != nil {
   393  		t.Logf("%s\n", got)
   394  		t.Fatal(err)
   395  	}
   396  	want := "OK\n"
   397  	if string(got) != want {
   398  		t.Errorf("expected %q got %s", want, got)
   399  	}
   400  }
   401  
   402  func TestCgoNumGoroutine(t *testing.T) {
   403  	switch runtime.GOOS {
   404  	case "windows", "plan9":
   405  		t.Skipf("skipping numgoroutine test on %s", runtime.GOOS)
   406  	}
   407  	t.Parallel()
   408  	got := runTestProg(t, "testprogcgo", "NumGoroutine")
   409  	want := "OK\n"
   410  	if got != want {
   411  		t.Errorf("expected %q got %v", want, got)
   412  	}
   413  }
   414  
   415  func TestCatchPanic(t *testing.T) {
   416  	t.Parallel()
   417  	switch runtime.GOOS {
   418  	case "plan9", "windows":
   419  		t.Skipf("no signals on %s", runtime.GOOS)
   420  	case "darwin":
   421  		if runtime.GOARCH == "amd64" {
   422  			t.Skipf("crash() on darwin/amd64 doesn't raise SIGABRT")
   423  		}
   424  	}
   425  
   426  	testenv.MustHaveGoRun(t)
   427  
   428  	exe, err := buildTestProg(t, "testprogcgo")
   429  	if err != nil {
   430  		t.Fatal(err)
   431  	}
   432  
   433  	for _, early := range []bool{true, false} {
   434  		cmd := testenv.CleanCmdEnv(exec.Command(exe, "CgoCatchPanic"))
   435  		// Make sure a panic results in a crash.
   436  		cmd.Env = append(cmd.Env, "GOTRACEBACK=crash")
   437  		if early {
   438  			// Tell testprogcgo to install an early signal handler for SIGABRT
   439  			cmd.Env = append(cmd.Env, "CGOCATCHPANIC_EARLY_HANDLER=1")
   440  		}
   441  		if out, err := cmd.CombinedOutput(); err != nil {
   442  			t.Errorf("testprogcgo CgoCatchPanic failed: %v\n%s", err, out)
   443  		}
   444  	}
   445  }
   446  
   447  func TestCgoLockOSThreadExit(t *testing.T) {
   448  	switch runtime.GOOS {
   449  	case "plan9", "windows":
   450  		t.Skipf("no pthreads on %s", runtime.GOOS)
   451  	}
   452  	t.Parallel()
   453  	testLockOSThreadExit(t, "testprogcgo")
   454  }
   455  
   456  func TestWindowsStackMemoryCgo(t *testing.T) {
   457  	if runtime.GOOS != "windows" {
   458  		t.Skip("skipping windows specific test")
   459  	}
   460  	testenv.SkipFlaky(t, 22575)
   461  	o := runTestProg(t, "testprogcgo", "StackMemory")
   462  	stackUsage, err := strconv.Atoi(o)
   463  	if err != nil {
   464  		t.Fatalf("Failed to read stack usage: %v", err)
   465  	}
   466  	if expected, got := 100<<10, stackUsage; got > expected {
   467  		t.Fatalf("expected < %d bytes of memory per thread, got %d", expected, got)
   468  	}
   469  }
   470  
   471  func TestSigStackSwapping(t *testing.T) {
   472  	switch runtime.GOOS {
   473  	case "plan9", "windows":
   474  		t.Skipf("no sigaltstack on %s", runtime.GOOS)
   475  	}
   476  	t.Parallel()
   477  	got := runTestProg(t, "testprogcgo", "SigStack")
   478  	want := "OK\n"
   479  	if got != want {
   480  		t.Errorf("expected %q got %v", want, got)
   481  	}
   482  }
   483  
   484  func TestCgoTracebackSigpanic(t *testing.T) {
   485  	// Test unwinding over a sigpanic in C code without a C
   486  	// symbolizer. See issue #23576.
   487  	if runtime.GOOS == "windows" {
   488  		// On Windows if we get an exception in C code, we let
   489  		// the Windows exception handler unwind it, rather
   490  		// than injecting a sigpanic.
   491  		t.Skip("no sigpanic in C on windows")
   492  	}
   493  	t.Parallel()
   494  	got := runTestProg(t, "testprogcgo", "TracebackSigpanic")
   495  	want := "runtime.sigpanic"
   496  	if !strings.Contains(got, want) {
   497  		t.Fatalf("want failure containing %q. output:\n%s\n", want, got)
   498  	}
   499  	nowant := "unexpected return pc"
   500  	if strings.Contains(got, nowant) {
   501  		t.Fatalf("failure incorrectly contains %q. output:\n%s\n", nowant, got)
   502  	}
   503  }
   504  
   505  // Test that C code called via cgo can use large Windows thread stacks
   506  // and call back in to Go without crashing. See issue #20975.
   507  //
   508  // See also TestBigStackCallbackSyscall.
   509  func TestBigStackCallbackCgo(t *testing.T) {
   510  	if runtime.GOOS != "windows" {
   511  		t.Skip("skipping windows specific test")
   512  	}
   513  	t.Parallel()
   514  	got := runTestProg(t, "testprogcgo", "BigStack")
   515  	want := "OK\n"
   516  	if got != want {
   517  		t.Errorf("expected %q got %v", want, got)
   518  	}
   519  }
   520  
   521  func nextTrace(lines []string) ([]string, []string) {
   522  	var trace []string
   523  	for n, line := range lines {
   524  		if strings.HasPrefix(line, "---") {
   525  			return trace, lines[n+1:]
   526  		}
   527  		fields := strings.Fields(strings.TrimSpace(line))
   528  		if len(fields) == 0 {
   529  			continue
   530  		}
   531  		// Last field contains the function name.
   532  		trace = append(trace, fields[len(fields)-1])
   533  	}
   534  	return nil, nil
   535  }
   536  
   537  func findTrace(text, top string) []string {
   538  	lines := strings.Split(text, "\n")
   539  	_, lines = nextTrace(lines) // Skip the header.
   540  	for len(lines) > 0 {
   541  		var t []string
   542  		t, lines = nextTrace(lines)
   543  		if len(t) == 0 {
   544  			continue
   545  		}
   546  		if t[0] == top {
   547  			return t
   548  		}
   549  	}
   550  	return nil
   551  }