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