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