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 }