github.com/AESNooper/go/src@v0.0.0-20220218095104-b56a4ab1bbbb/runtime/crash_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  package runtime_test
     6  
     7  import (
     8  	"bytes"
     9  	"errors"
    10  	"flag"
    11  	"fmt"
    12  	"internal/testenv"
    13  	"os"
    14  	"os/exec"
    15  	"path/filepath"
    16  	"regexp"
    17  	"runtime"
    18  	"strconv"
    19  	"strings"
    20  	"sync"
    21  	"testing"
    22  	"time"
    23  )
    24  
    25  var toRemove []string
    26  
    27  func TestMain(m *testing.M) {
    28  	status := m.Run()
    29  	for _, file := range toRemove {
    30  		os.RemoveAll(file)
    31  	}
    32  	os.Exit(status)
    33  }
    34  
    35  var testprog struct {
    36  	sync.Mutex
    37  	dir    string
    38  	target map[string]*buildexe
    39  }
    40  
    41  type buildexe struct {
    42  	once sync.Once
    43  	exe  string
    44  	err  error
    45  }
    46  
    47  func runTestProg(t *testing.T, binary, name string, env ...string) string {
    48  	if *flagQuick {
    49  		t.Skip("-quick")
    50  	}
    51  
    52  	testenv.MustHaveGoBuild(t)
    53  
    54  	exe, err := buildTestProg(t, binary)
    55  	if err != nil {
    56  		t.Fatal(err)
    57  	}
    58  
    59  	return runBuiltTestProg(t, exe, name, env...)
    60  }
    61  
    62  func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string {
    63  	if *flagQuick {
    64  		t.Skip("-quick")
    65  	}
    66  
    67  	testenv.MustHaveGoBuild(t)
    68  
    69  	cmd := testenv.CleanCmdEnv(exec.Command(exe, name))
    70  	cmd.Env = append(cmd.Env, env...)
    71  	if testing.Short() {
    72  		cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1")
    73  	}
    74  	var b bytes.Buffer
    75  	cmd.Stdout = &b
    76  	cmd.Stderr = &b
    77  	if err := cmd.Start(); err != nil {
    78  		t.Fatalf("starting %s %s: %v", exe, name, err)
    79  	}
    80  
    81  	// If the process doesn't complete within 1 minute,
    82  	// assume it is hanging and kill it to get a stack trace.
    83  	p := cmd.Process
    84  	done := make(chan bool)
    85  	go func() {
    86  		scale := 1
    87  		// This GOARCH/GOOS test is copied from cmd/dist/test.go.
    88  		// TODO(iant): Have cmd/dist update the environment variable.
    89  		if runtime.GOARCH == "arm" || runtime.GOOS == "windows" {
    90  			scale = 2
    91  		}
    92  		if s := os.Getenv("GO_TEST_TIMEOUT_SCALE"); s != "" {
    93  			if sc, err := strconv.Atoi(s); err == nil {
    94  				scale = sc
    95  			}
    96  		}
    97  
    98  		select {
    99  		case <-done:
   100  		case <-time.After(time.Duration(scale) * time.Minute):
   101  			p.Signal(sigquit)
   102  		}
   103  	}()
   104  
   105  	if err := cmd.Wait(); err != nil {
   106  		t.Logf("%s %s exit status: %v", exe, name, err)
   107  	}
   108  	close(done)
   109  
   110  	return b.String()
   111  }
   112  
   113  var serializeBuild = make(chan bool, 2)
   114  
   115  func buildTestProg(t *testing.T, binary string, flags ...string) (string, error) {
   116  	if *flagQuick {
   117  		t.Skip("-quick")
   118  	}
   119  	testenv.MustHaveGoBuild(t)
   120  
   121  	testprog.Lock()
   122  	if testprog.dir == "" {
   123  		dir, err := os.MkdirTemp("", "go-build")
   124  		if err != nil {
   125  			t.Fatalf("failed to create temp directory: %v", err)
   126  		}
   127  		testprog.dir = dir
   128  		toRemove = append(toRemove, dir)
   129  	}
   130  
   131  	if testprog.target == nil {
   132  		testprog.target = make(map[string]*buildexe)
   133  	}
   134  	name := binary
   135  	if len(flags) > 0 {
   136  		name += "_" + strings.Join(flags, "_")
   137  	}
   138  	target, ok := testprog.target[name]
   139  	if !ok {
   140  		target = &buildexe{}
   141  		testprog.target[name] = target
   142  	}
   143  
   144  	dir := testprog.dir
   145  
   146  	// Unlock testprog while actually building, so that other
   147  	// tests can look up executables that were already built.
   148  	testprog.Unlock()
   149  
   150  	target.once.Do(func() {
   151  		// Only do two "go build"'s at a time,
   152  		// to keep load from getting too high.
   153  		serializeBuild <- true
   154  		defer func() { <-serializeBuild }()
   155  
   156  		// Don't get confused if testenv.GoToolPath calls t.Skip.
   157  		target.err = errors.New("building test called t.Skip")
   158  
   159  		exe := filepath.Join(dir, name+".exe")
   160  
   161  		t.Logf("running go build -o %s %s", exe, strings.Join(flags, " "))
   162  		cmd := exec.Command(testenv.GoToolPath(t), append([]string{"build", "-o", exe}, flags...)...)
   163  		cmd.Dir = "testdata/" + binary
   164  		out, err := testenv.CleanCmdEnv(cmd).CombinedOutput()
   165  		if err != nil {
   166  			target.err = fmt.Errorf("building %s %v: %v\n%s", binary, flags, err, out)
   167  		} else {
   168  			target.exe = exe
   169  			target.err = nil
   170  		}
   171  	})
   172  
   173  	return target.exe, target.err
   174  }
   175  
   176  func TestVDSO(t *testing.T) {
   177  	t.Parallel()
   178  	output := runTestProg(t, "testprog", "SignalInVDSO")
   179  	want := "success\n"
   180  	if output != want {
   181  		t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
   182  	}
   183  }
   184  
   185  func testCrashHandler(t *testing.T, cgo bool) {
   186  	type crashTest struct {
   187  		Cgo bool
   188  	}
   189  	var output string
   190  	if cgo {
   191  		output = runTestProg(t, "testprogcgo", "Crash")
   192  	} else {
   193  		output = runTestProg(t, "testprog", "Crash")
   194  	}
   195  	want := "main: recovered done\nnew-thread: recovered done\nsecond-new-thread: recovered done\nmain-again: recovered done\n"
   196  	if output != want {
   197  		t.Fatalf("output:\n%s\n\nwanted:\n%s", output, want)
   198  	}
   199  }
   200  
   201  func TestCrashHandler(t *testing.T) {
   202  	testCrashHandler(t, false)
   203  }
   204  
   205  func testDeadlock(t *testing.T, name string) {
   206  	// External linking brings in cgo, causing deadlock detection not working.
   207  	testenv.MustInternalLink(t)
   208  
   209  	output := runTestProg(t, "testprog", name)
   210  	want := "fatal error: all goroutines are asleep - deadlock!\n"
   211  	if !strings.HasPrefix(output, want) {
   212  		t.Fatalf("output does not start with %q:\n%s", want, output)
   213  	}
   214  }
   215  
   216  func TestSimpleDeadlock(t *testing.T) {
   217  	testDeadlock(t, "SimpleDeadlock")
   218  }
   219  
   220  func TestInitDeadlock(t *testing.T) {
   221  	testDeadlock(t, "InitDeadlock")
   222  }
   223  
   224  func TestLockedDeadlock(t *testing.T) {
   225  	testDeadlock(t, "LockedDeadlock")
   226  }
   227  
   228  func TestLockedDeadlock2(t *testing.T) {
   229  	testDeadlock(t, "LockedDeadlock2")
   230  }
   231  
   232  func TestGoexitDeadlock(t *testing.T) {
   233  	// External linking brings in cgo, causing deadlock detection not working.
   234  	testenv.MustInternalLink(t)
   235  
   236  	output := runTestProg(t, "testprog", "GoexitDeadlock")
   237  	want := "no goroutines (main called runtime.Goexit) - deadlock!"
   238  	if !strings.Contains(output, want) {
   239  		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
   240  	}
   241  }
   242  
   243  func TestStackOverflow(t *testing.T) {
   244  	output := runTestProg(t, "testprog", "StackOverflow")
   245  	want := []string{
   246  		"runtime: goroutine stack exceeds 1474560-byte limit\n",
   247  		"fatal error: stack overflow",
   248  		// information about the current SP and stack bounds
   249  		"runtime: sp=",
   250  		"stack=[",
   251  	}
   252  	if !strings.HasPrefix(output, want[0]) {
   253  		t.Errorf("output does not start with %q", want[0])
   254  	}
   255  	for _, s := range want[1:] {
   256  		if !strings.Contains(output, s) {
   257  			t.Errorf("output does not contain %q", s)
   258  		}
   259  	}
   260  	if t.Failed() {
   261  		t.Logf("output:\n%s", output)
   262  	}
   263  }
   264  
   265  func TestThreadExhaustion(t *testing.T) {
   266  	output := runTestProg(t, "testprog", "ThreadExhaustion")
   267  	want := "runtime: program exceeds 10-thread limit\nfatal error: thread exhaustion"
   268  	if !strings.HasPrefix(output, want) {
   269  		t.Fatalf("output does not start with %q:\n%s", want, output)
   270  	}
   271  }
   272  
   273  func TestRecursivePanic(t *testing.T) {
   274  	output := runTestProg(t, "testprog", "RecursivePanic")
   275  	want := `wrap: bad
   276  panic: again
   277  
   278  `
   279  	if !strings.HasPrefix(output, want) {
   280  		t.Fatalf("output does not start with %q:\n%s", want, output)
   281  	}
   282  
   283  }
   284  
   285  func TestRecursivePanic2(t *testing.T) {
   286  	output := runTestProg(t, "testprog", "RecursivePanic2")
   287  	want := `first panic
   288  second panic
   289  panic: third panic
   290  
   291  `
   292  	if !strings.HasPrefix(output, want) {
   293  		t.Fatalf("output does not start with %q:\n%s", want, output)
   294  	}
   295  
   296  }
   297  
   298  func TestRecursivePanic3(t *testing.T) {
   299  	output := runTestProg(t, "testprog", "RecursivePanic3")
   300  	want := `panic: first panic
   301  
   302  `
   303  	if !strings.HasPrefix(output, want) {
   304  		t.Fatalf("output does not start with %q:\n%s", want, output)
   305  	}
   306  
   307  }
   308  
   309  func TestRecursivePanic4(t *testing.T) {
   310  	output := runTestProg(t, "testprog", "RecursivePanic4")
   311  	want := `panic: first panic [recovered]
   312  	panic: second panic
   313  `
   314  	if !strings.HasPrefix(output, want) {
   315  		t.Fatalf("output does not start with %q:\n%s", want, output)
   316  	}
   317  
   318  }
   319  
   320  func TestRecursivePanic5(t *testing.T) {
   321  	output := runTestProg(t, "testprog", "RecursivePanic5")
   322  	want := `first panic
   323  second panic
   324  panic: third panic
   325  `
   326  	if !strings.HasPrefix(output, want) {
   327  		t.Fatalf("output does not start with %q:\n%s", want, output)
   328  	}
   329  
   330  }
   331  
   332  func TestGoexitCrash(t *testing.T) {
   333  	// External linking brings in cgo, causing deadlock detection not working.
   334  	testenv.MustInternalLink(t)
   335  
   336  	output := runTestProg(t, "testprog", "GoexitExit")
   337  	want := "no goroutines (main called runtime.Goexit) - deadlock!"
   338  	if !strings.Contains(output, want) {
   339  		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
   340  	}
   341  }
   342  
   343  func TestGoexitDefer(t *testing.T) {
   344  	c := make(chan struct{})
   345  	go func() {
   346  		defer func() {
   347  			r := recover()
   348  			if r != nil {
   349  				t.Errorf("non-nil recover during Goexit")
   350  			}
   351  			c <- struct{}{}
   352  		}()
   353  		runtime.Goexit()
   354  	}()
   355  	// Note: if the defer fails to run, we will get a deadlock here
   356  	<-c
   357  }
   358  
   359  func TestGoNil(t *testing.T) {
   360  	output := runTestProg(t, "testprog", "GoNil")
   361  	want := "go of nil func value"
   362  	if !strings.Contains(output, want) {
   363  		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
   364  	}
   365  }
   366  
   367  func TestMainGoroutineID(t *testing.T) {
   368  	output := runTestProg(t, "testprog", "MainGoroutineID")
   369  	want := "panic: test\n\ngoroutine 1 [running]:\n"
   370  	if !strings.HasPrefix(output, want) {
   371  		t.Fatalf("output does not start with %q:\n%s", want, output)
   372  	}
   373  }
   374  
   375  func TestNoHelperGoroutines(t *testing.T) {
   376  	output := runTestProg(t, "testprog", "NoHelperGoroutines")
   377  	matches := regexp.MustCompile(`goroutine [0-9]+ \[`).FindAllStringSubmatch(output, -1)
   378  	if len(matches) != 1 || matches[0][0] != "goroutine 1 [" {
   379  		t.Fatalf("want to see only goroutine 1, see:\n%s", output)
   380  	}
   381  }
   382  
   383  func TestBreakpoint(t *testing.T) {
   384  	output := runTestProg(t, "testprog", "Breakpoint")
   385  	// If runtime.Breakpoint() is inlined, then the stack trace prints
   386  	// "runtime.Breakpoint(...)" instead of "runtime.Breakpoint()".
   387  	want := "runtime.Breakpoint("
   388  	if !strings.Contains(output, want) {
   389  		t.Fatalf("output:\n%s\n\nwant output containing: %s", output, want)
   390  	}
   391  }
   392  
   393  func TestGoexitInPanic(t *testing.T) {
   394  	// External linking brings in cgo, causing deadlock detection not working.
   395  	testenv.MustInternalLink(t)
   396  
   397  	// see issue 8774: this code used to trigger an infinite recursion
   398  	output := runTestProg(t, "testprog", "GoexitInPanic")
   399  	want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
   400  	if !strings.HasPrefix(output, want) {
   401  		t.Fatalf("output does not start with %q:\n%s", want, output)
   402  	}
   403  }
   404  
   405  // Issue 14965: Runtime panics should be of type runtime.Error
   406  func TestRuntimePanicWithRuntimeError(t *testing.T) {
   407  	testCases := [...]func(){
   408  		0: func() {
   409  			var m map[uint64]bool
   410  			m[1234] = true
   411  		},
   412  		1: func() {
   413  			ch := make(chan struct{})
   414  			close(ch)
   415  			close(ch)
   416  		},
   417  		2: func() {
   418  			var ch = make(chan struct{})
   419  			close(ch)
   420  			ch <- struct{}{}
   421  		},
   422  		3: func() {
   423  			var s = make([]int, 2)
   424  			_ = s[2]
   425  		},
   426  		4: func() {
   427  			n := -1
   428  			_ = make(chan bool, n)
   429  		},
   430  		5: func() {
   431  			close((chan bool)(nil))
   432  		},
   433  	}
   434  
   435  	for i, fn := range testCases {
   436  		got := panicValue(fn)
   437  		if _, ok := got.(runtime.Error); !ok {
   438  			t.Errorf("test #%d: recovered value %v(type %T) does not implement runtime.Error", i, got, got)
   439  		}
   440  	}
   441  }
   442  
   443  func panicValue(fn func()) (recovered interface{}) {
   444  	defer func() {
   445  		recovered = recover()
   446  	}()
   447  	fn()
   448  	return
   449  }
   450  
   451  func TestPanicAfterGoexit(t *testing.T) {
   452  	// an uncaught panic should still work after goexit
   453  	output := runTestProg(t, "testprog", "PanicAfterGoexit")
   454  	want := "panic: hello"
   455  	if !strings.HasPrefix(output, want) {
   456  		t.Fatalf("output does not start with %q:\n%s", want, output)
   457  	}
   458  }
   459  
   460  func TestRecoveredPanicAfterGoexit(t *testing.T) {
   461  	// External linking brings in cgo, causing deadlock detection not working.
   462  	testenv.MustInternalLink(t)
   463  
   464  	output := runTestProg(t, "testprog", "RecoveredPanicAfterGoexit")
   465  	want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
   466  	if !strings.HasPrefix(output, want) {
   467  		t.Fatalf("output does not start with %q:\n%s", want, output)
   468  	}
   469  }
   470  
   471  func TestRecoverBeforePanicAfterGoexit(t *testing.T) {
   472  	// External linking brings in cgo, causing deadlock detection not working.
   473  	testenv.MustInternalLink(t)
   474  
   475  	t.Parallel()
   476  	output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit")
   477  	want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
   478  	if !strings.HasPrefix(output, want) {
   479  		t.Fatalf("output does not start with %q:\n%s", want, output)
   480  	}
   481  }
   482  
   483  func TestRecoverBeforePanicAfterGoexit2(t *testing.T) {
   484  	// External linking brings in cgo, causing deadlock detection not working.
   485  	testenv.MustInternalLink(t)
   486  
   487  	t.Parallel()
   488  	output := runTestProg(t, "testprog", "RecoverBeforePanicAfterGoexit2")
   489  	want := "fatal error: no goroutines (main called runtime.Goexit) - deadlock!"
   490  	if !strings.HasPrefix(output, want) {
   491  		t.Fatalf("output does not start with %q:\n%s", want, output)
   492  	}
   493  }
   494  
   495  func TestNetpollDeadlock(t *testing.T) {
   496  	t.Parallel()
   497  	output := runTestProg(t, "testprognet", "NetpollDeadlock")
   498  	want := "done\n"
   499  	if !strings.HasSuffix(output, want) {
   500  		t.Fatalf("output does not start with %q:\n%s", want, output)
   501  	}
   502  }
   503  
   504  func TestPanicTraceback(t *testing.T) {
   505  	t.Parallel()
   506  	output := runTestProg(t, "testprog", "PanicTraceback")
   507  	want := "panic: hello\n\tpanic: panic pt2\n\tpanic: panic pt1\n"
   508  	if !strings.HasPrefix(output, want) {
   509  		t.Fatalf("output does not start with %q:\n%s", want, output)
   510  	}
   511  
   512  	// Check functions in the traceback.
   513  	fns := []string{"main.pt1.func1", "panic", "main.pt2.func1", "panic", "main.pt2", "main.pt1"}
   514  	for _, fn := range fns {
   515  		re := regexp.MustCompile(`(?m)^` + regexp.QuoteMeta(fn) + `\(.*\n`)
   516  		idx := re.FindStringIndex(output)
   517  		if idx == nil {
   518  			t.Fatalf("expected %q function in traceback:\n%s", fn, output)
   519  		}
   520  		output = output[idx[1]:]
   521  	}
   522  }
   523  
   524  func testPanicDeadlock(t *testing.T, name string, want string) {
   525  	// test issue 14432
   526  	output := runTestProg(t, "testprog", name)
   527  	if !strings.HasPrefix(output, want) {
   528  		t.Fatalf("output does not start with %q:\n%s", want, output)
   529  	}
   530  }
   531  
   532  func TestPanicDeadlockGosched(t *testing.T) {
   533  	testPanicDeadlock(t, "GoschedInPanic", "panic: errorThatGosched\n\n")
   534  }
   535  
   536  func TestPanicDeadlockSyscall(t *testing.T) {
   537  	testPanicDeadlock(t, "SyscallInPanic", "1\n2\npanic: 3\n\n")
   538  }
   539  
   540  func TestPanicLoop(t *testing.T) {
   541  	output := runTestProg(t, "testprog", "PanicLoop")
   542  	if want := "panic while printing panic value"; !strings.Contains(output, want) {
   543  		t.Errorf("output does not contain %q:\n%s", want, output)
   544  	}
   545  }
   546  
   547  func TestMemPprof(t *testing.T) {
   548  	testenv.MustHaveGoRun(t)
   549  
   550  	exe, err := buildTestProg(t, "testprog")
   551  	if err != nil {
   552  		t.Fatal(err)
   553  	}
   554  
   555  	got, err := testenv.CleanCmdEnv(exec.Command(exe, "MemProf")).CombinedOutput()
   556  	if err != nil {
   557  		t.Fatal(err)
   558  	}
   559  	fn := strings.TrimSpace(string(got))
   560  	defer os.Remove(fn)
   561  
   562  	for try := 0; try < 2; try++ {
   563  		cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-alloc_space", "-top"))
   564  		// Check that pprof works both with and without explicit executable on command line.
   565  		if try == 0 {
   566  			cmd.Args = append(cmd.Args, exe, fn)
   567  		} else {
   568  			cmd.Args = append(cmd.Args, fn)
   569  		}
   570  		found := false
   571  		for i, e := range cmd.Env {
   572  			if strings.HasPrefix(e, "PPROF_TMPDIR=") {
   573  				cmd.Env[i] = "PPROF_TMPDIR=" + os.TempDir()
   574  				found = true
   575  				break
   576  			}
   577  		}
   578  		if !found {
   579  			cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   580  		}
   581  
   582  		top, err := cmd.CombinedOutput()
   583  		t.Logf("%s:\n%s", cmd.Args, top)
   584  		if err != nil {
   585  			t.Error(err)
   586  		} else if !bytes.Contains(top, []byte("MemProf")) {
   587  			t.Error("missing MemProf in pprof output")
   588  		}
   589  	}
   590  }
   591  
   592  var concurrentMapTest = flag.Bool("run_concurrent_map_tests", false, "also run flaky concurrent map tests")
   593  
   594  func TestConcurrentMapWrites(t *testing.T) {
   595  	if !*concurrentMapTest {
   596  		t.Skip("skipping without -run_concurrent_map_tests")
   597  	}
   598  	testenv.MustHaveGoRun(t)
   599  	output := runTestProg(t, "testprog", "concurrentMapWrites")
   600  	want := "fatal error: concurrent map writes"
   601  	if !strings.HasPrefix(output, want) {
   602  		t.Fatalf("output does not start with %q:\n%s", want, output)
   603  	}
   604  }
   605  func TestConcurrentMapReadWrite(t *testing.T) {
   606  	if !*concurrentMapTest {
   607  		t.Skip("skipping without -run_concurrent_map_tests")
   608  	}
   609  	testenv.MustHaveGoRun(t)
   610  	output := runTestProg(t, "testprog", "concurrentMapReadWrite")
   611  	want := "fatal error: concurrent map read and map write"
   612  	if !strings.HasPrefix(output, want) {
   613  		t.Fatalf("output does not start with %q:\n%s", want, output)
   614  	}
   615  }
   616  func TestConcurrentMapIterateWrite(t *testing.T) {
   617  	if !*concurrentMapTest {
   618  		t.Skip("skipping without -run_concurrent_map_tests")
   619  	}
   620  	testenv.MustHaveGoRun(t)
   621  	output := runTestProg(t, "testprog", "concurrentMapIterateWrite")
   622  	want := "fatal error: concurrent map iteration and map write"
   623  	if !strings.HasPrefix(output, want) {
   624  		t.Fatalf("output does not start with %q:\n%s", want, output)
   625  	}
   626  }
   627  
   628  type point struct {
   629  	x, y *int
   630  }
   631  
   632  func (p *point) negate() {
   633  	*p.x = *p.x * -1
   634  	*p.y = *p.y * -1
   635  }
   636  
   637  // Test for issue #10152.
   638  func TestPanicInlined(t *testing.T) {
   639  	defer func() {
   640  		r := recover()
   641  		if r == nil {
   642  			t.Fatalf("recover failed")
   643  		}
   644  		buf := make([]byte, 2048)
   645  		n := runtime.Stack(buf, false)
   646  		buf = buf[:n]
   647  		if !bytes.Contains(buf, []byte("(*point).negate(")) {
   648  			t.Fatalf("expecting stack trace to contain call to (*point).negate()")
   649  		}
   650  	}()
   651  
   652  	pt := new(point)
   653  	pt.negate()
   654  }
   655  
   656  // Test for issues #3934 and #20018.
   657  // We want to delay exiting until a panic print is complete.
   658  func TestPanicRace(t *testing.T) {
   659  	testenv.MustHaveGoRun(t)
   660  
   661  	exe, err := buildTestProg(t, "testprog")
   662  	if err != nil {
   663  		t.Fatal(err)
   664  	}
   665  
   666  	// The test is intentionally racy, and in my testing does not
   667  	// produce the expected output about 0.05% of the time.
   668  	// So run the program in a loop and only fail the test if we
   669  	// get the wrong output ten times in a row.
   670  	const tries = 10
   671  retry:
   672  	for i := 0; i < tries; i++ {
   673  		got, err := testenv.CleanCmdEnv(exec.Command(exe, "PanicRace")).CombinedOutput()
   674  		if err == nil {
   675  			t.Logf("try %d: program exited successfully, should have failed", i+1)
   676  			continue
   677  		}
   678  
   679  		if i > 0 {
   680  			t.Logf("try %d:\n", i+1)
   681  		}
   682  		t.Logf("%s\n", got)
   683  
   684  		wants := []string{
   685  			"panic: crash",
   686  			"PanicRace",
   687  			"created by ",
   688  		}
   689  		for _, want := range wants {
   690  			if !bytes.Contains(got, []byte(want)) {
   691  				t.Logf("did not find expected string %q", want)
   692  				continue retry
   693  			}
   694  		}
   695  
   696  		// Test generated expected output.
   697  		return
   698  	}
   699  	t.Errorf("test ran %d times without producing expected output", tries)
   700  }
   701  
   702  func TestBadTraceback(t *testing.T) {
   703  	output := runTestProg(t, "testprog", "BadTraceback")
   704  	for _, want := range []string{
   705  		"runtime: unexpected return pc",
   706  		"called from 0xbad",
   707  		"00000bad",    // Smashed LR in hex dump
   708  		"<main.badLR", // Symbolization in hex dump (badLR1 or badLR2)
   709  	} {
   710  		if !strings.Contains(output, want) {
   711  			t.Errorf("output does not contain %q:\n%s", want, output)
   712  		}
   713  	}
   714  }
   715  
   716  func TestTimePprof(t *testing.T) {
   717  	// This test is unreliable on any system in which nanotime
   718  	// calls into libc.
   719  	switch runtime.GOOS {
   720  	case "aix", "darwin", "illumos", "openbsd", "solaris":
   721  		t.Skipf("skipping on %s because nanotime calls libc", runtime.GOOS)
   722  	}
   723  
   724  	// Pass GOTRACEBACK for issue #41120 to try to get more
   725  	// information on timeout.
   726  	fn := runTestProg(t, "testprog", "TimeProf", "GOTRACEBACK=crash")
   727  	fn = strings.TrimSpace(fn)
   728  	defer os.Remove(fn)
   729  
   730  	cmd := testenv.CleanCmdEnv(exec.Command(testenv.GoToolPath(t), "tool", "pprof", "-top", "-nodecount=1", fn))
   731  	cmd.Env = append(cmd.Env, "PPROF_TMPDIR="+os.TempDir())
   732  	top, err := cmd.CombinedOutput()
   733  	t.Logf("%s", top)
   734  	if err != nil {
   735  		t.Error(err)
   736  	} else if bytes.Contains(top, []byte("ExternalCode")) {
   737  		t.Error("profiler refers to ExternalCode")
   738  	}
   739  }
   740  
   741  // Test that runtime.abort does so.
   742  func TestAbort(t *testing.T) {
   743  	// Pass GOTRACEBACK to ensure we get runtime frames.
   744  	output := runTestProg(t, "testprog", "Abort", "GOTRACEBACK=system")
   745  	if want := "runtime.abort"; !strings.Contains(output, want) {
   746  		t.Errorf("output does not contain %q:\n%s", want, output)
   747  	}
   748  	if strings.Contains(output, "BAD") {
   749  		t.Errorf("output contains BAD:\n%s", output)
   750  	}
   751  	// Check that it's a signal traceback.
   752  	want := "PC="
   753  	// For systems that use a breakpoint, check specifically for that.
   754  	switch runtime.GOARCH {
   755  	case "386", "amd64":
   756  		switch runtime.GOOS {
   757  		case "plan9":
   758  			want = "sys: breakpoint"
   759  		case "windows":
   760  			want = "Exception 0x80000003"
   761  		default:
   762  			want = "SIGTRAP"
   763  		}
   764  	}
   765  	if !strings.Contains(output, want) {
   766  		t.Errorf("output does not contain %q:\n%s", want, output)
   767  	}
   768  }
   769  
   770  // For TestRuntimePanic: test a panic in the runtime package without
   771  // involving the testing harness.
   772  func init() {
   773  	if os.Getenv("GO_TEST_RUNTIME_PANIC") == "1" {
   774  		defer func() {
   775  			if r := recover(); r != nil {
   776  				// We expect to crash, so exit 0
   777  				// to indicate failure.
   778  				os.Exit(0)
   779  			}
   780  		}()
   781  		runtime.PanicForTesting(nil, 1)
   782  		// We expect to crash, so exit 0 to indicate failure.
   783  		os.Exit(0)
   784  	}
   785  }
   786  
   787  func TestRuntimePanic(t *testing.T) {
   788  	testenv.MustHaveExec(t)
   789  	cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestRuntimePanic"))
   790  	cmd.Env = append(cmd.Env, "GO_TEST_RUNTIME_PANIC=1")
   791  	out, err := cmd.CombinedOutput()
   792  	t.Logf("%s", out)
   793  	if err == nil {
   794  		t.Error("child process did not fail")
   795  	} else if want := "runtime.unexportedPanicForTesting"; !bytes.Contains(out, []byte(want)) {
   796  		t.Errorf("output did not contain expected string %q", want)
   797  	}
   798  }
   799  
   800  // Test that g0 stack overflows are handled gracefully.
   801  func TestG0StackOverflow(t *testing.T) {
   802  	testenv.MustHaveExec(t)
   803  
   804  	switch runtime.GOOS {
   805  	case "darwin", "dragonfly", "freebsd", "linux", "netbsd", "openbsd", "android":
   806  		t.Skipf("g0 stack is wrong on pthread platforms (see golang.org/issue/26061)")
   807  	}
   808  
   809  	if os.Getenv("TEST_G0_STACK_OVERFLOW") != "1" {
   810  		cmd := testenv.CleanCmdEnv(exec.Command(os.Args[0], "-test.run=TestG0StackOverflow", "-test.v"))
   811  		cmd.Env = append(cmd.Env, "TEST_G0_STACK_OVERFLOW=1")
   812  		out, err := cmd.CombinedOutput()
   813  		// Don't check err since it's expected to crash.
   814  		if n := strings.Count(string(out), "morestack on g0\n"); n != 1 {
   815  			t.Fatalf("%s\n(exit status %v)", out, err)
   816  		}
   817  		// Check that it's a signal-style traceback.
   818  		if runtime.GOOS != "windows" {
   819  			if want := "PC="; !strings.Contains(string(out), want) {
   820  				t.Errorf("output does not contain %q:\n%s", want, out)
   821  			}
   822  		}
   823  		return
   824  	}
   825  
   826  	runtime.G0StackOverflow()
   827  }
   828  
   829  // Test that panic message is not clobbered.
   830  // See issue 30150.
   831  func TestDoublePanic(t *testing.T) {
   832  	output := runTestProg(t, "testprog", "DoublePanic", "GODEBUG=clobberfree=1")
   833  	wants := []string{"panic: XXX", "panic: YYY"}
   834  	for _, want := range wants {
   835  		if !strings.Contains(output, want) {
   836  			t.Errorf("output:\n%s\n\nwant output containing: %s", output, want)
   837  		}
   838  	}
   839  }