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