diff --git a/src/runtime/crash_unix_test.go b/src/runtime/crash_unix_test.go index b5cc910ad1f..9469d5e6a64 100644 --- a/src/runtime/crash_unix_test.go +++ b/src/runtime/crash_unix_test.go @@ -13,7 +13,6 @@ import ( "io" "os" "os/exec" - "path/filepath" "runtime" "strings" "sync" @@ -78,27 +77,14 @@ func TestCrashDumpsAllThreads(t *testing.T) { t.Skip("skipping; SIGQUIT is blocked, see golang.org/issue/19196") } - // We don't use executeTest because we need to kill the - // program while it is running. - testenv.MustHaveGoBuild(t) - t.Parallel() - - dir := t.TempDir() - - if err := os.WriteFile(filepath.Join(dir, "main.go"), []byte(crashDumpsAllThreadsSource), 0666); err != nil { - t.Fatalf("failed to create Go file: %v", err) - } - - cmd := exec.Command(testenv.GoToolPath(t), "build", "-o", "a.exe", "main.go") - cmd.Dir = dir - out, err := testenv.CleanCmdEnv(cmd).CombinedOutput() + exe, err := buildTestProg(t, "testprog") if err != nil { - t.Fatalf("building source: %v\n%s", err, out) + t.Fatal(err) } - cmd = exec.Command(filepath.Join(dir, "a.exe")) + cmd := exec.Command(exe, "CrashDumpsAllThreads") cmd = testenv.CleanCmdEnv(cmd) cmd.Env = append(cmd.Env, "GOTRACEBACK=crash", @@ -120,9 +106,12 @@ func TestCrashDumpsAllThreads(t *testing.T) { if err != nil { t.Fatal(err) } + defer rp.Close() + cmd.ExtraFiles = []*os.File{wp} if err := cmd.Start(); err != nil { + wp.Close() t.Fatalf("starting program: %v", err) } @@ -144,56 +133,14 @@ func TestCrashDumpsAllThreads(t *testing.T) { // We want to see a stack trace for each thread. // Before https://golang.org/cl/2811 running threads would say // "goroutine running on other thread; stack unavailable". - out = outbuf.Bytes() - n := bytes.Count(out, []byte("main.loop(")) + out := outbuf.Bytes() + n := bytes.Count(out, []byte("main.crashDumpsAllThreadsLoop(")) if n != 4 { t.Errorf("found %d instances of main.loop; expected 4", n) t.Logf("%s", out) } } -const crashDumpsAllThreadsSource = ` -package main - -import ( - "fmt" - "os" - "runtime" -) - -func main() { - const count = 4 - runtime.GOMAXPROCS(count + 1) - - chans := make([]chan bool, count) - for i := range chans { - chans[i] = make(chan bool) - go loop(i, chans[i]) - } - - // Wait for all the goroutines to start executing. - for _, c := range chans { - <-c - } - - // Tell our parent that all the goroutines are executing. - if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { - fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) - os.Exit(2) - } - - select {} -} - -func loop(i int, c chan bool) { - close(c) - for { - for j := 0; j < 0x7fffffff; j++ { - } - } -} -` - func TestPanicSystemstack(t *testing.T) { // Test that GOTRACEBACK=crash prints both the system and user // stack of other threads. diff --git a/src/runtime/testdata/testprog/crashdump.go b/src/runtime/testdata/testprog/crashdump.go new file mode 100644 index 00000000000..bced397b8a3 --- /dev/null +++ b/src/runtime/testdata/testprog/crashdump.go @@ -0,0 +1,47 @@ +// Copyright 2021 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "fmt" + "os" + "runtime" +) + +func init() { + register("CrashDumpsAllThreads", CrashDumpsAllThreads) +} + +func CrashDumpsAllThreads() { + const count = 4 + runtime.GOMAXPROCS(count + 1) + + chans := make([]chan bool, count) + for i := range chans { + chans[i] = make(chan bool) + go crashDumpsAllThreadsLoop(i, chans[i]) + } + + // Wait for all the goroutines to start executing. + for _, c := range chans { + <-c + } + + // Tell our parent that all the goroutines are executing. + if _, err := os.NewFile(3, "pipe").WriteString("x"); err != nil { + fmt.Fprintf(os.Stderr, "write to pipe failed: %v\n", err) + os.Exit(2) + } + + select {} +} + +func crashDumpsAllThreadsLoop(i int, c chan bool) { + close(c) + for { + for j := 0; j < 0x7fffffff; j++ { + } + } +}