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