]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/crash_test.go
runtime: skip TestTimePprof if nanotime calls libc
[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         "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", "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 }