diff --git a/src/runtime/crash_test.go b/src/runtime/crash_test.go index 3782a927296..309777d6968 100644 --- a/src/runtime/crash_test.go +++ b/src/runtime/crash_test.go @@ -6,7 +6,6 @@ package runtime_test import ( "bytes" - "context" "errors" "flag" "fmt" @@ -66,15 +65,17 @@ func runBuiltTestProg(t *testing.T, exe, name string, env ...string) string { t.Skip("-quick") } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - cmd := testenv.CleanCmdEnv(testenv.CommandContext(t, ctx, exe, name)) + start := time.Now() + + cmd := testenv.CleanCmdEnv(testenv.Command(t, exe, name)) cmd.Env = append(cmd.Env, env...) if testing.Short() { cmd.Env = append(cmd.Env, "RUNTIME_TEST_SHORT=1") } out, err := cmd.CombinedOutput() - if err != nil { + if err == nil { + t.Logf("%v (%v): ok", cmd, time.Since(start)) + } else { if _, ok := err.(*exec.ExitError); ok { t.Logf("%v: %v", cmd, err) } else if errors.Is(err, exec.ErrWaitDelay) { diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index d3a30870c18..4e7c22762a1 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -6,7 +6,7 @@ package runtime_test import ( "bytes" - "context" + "flag" "fmt" "internal/testenv" "os" @@ -400,6 +400,15 @@ func TestGdbBacktrace(t *testing.T) { if runtime.GOOS == "netbsd" { testenv.SkipFlaky(t, 15603) } + if flag.Lookup("test.parallel").Value.(flag.Getter).Get().(int) < 2 { + // It is possible that this test will hang for a long time due to an + // apparent GDB bug reported in https://go.dev/issue/37405. + // If test parallelism is high enough, that might be ok: the other parallel + // tests will finish, and then this test will finish right before it would + // time out. However, if test are running sequentially, a hang in this test + // would likely cause the remaining tests to run out of time. + testenv.SkipFlaky(t, 37405) + } checkGdbEnvironment(t) t.Parallel() @@ -421,6 +430,7 @@ func TestGdbBacktrace(t *testing.T) { } // Execute gdb commands. + start := time.Now() args := []string{"-nx", "-batch", "-iex", "add-auto-load-safe-path " + filepath.Join(testenv.GOROOT(t), "src", "runtime"), "-ex", "set startup-with-shell off", @@ -430,9 +440,32 @@ func TestGdbBacktrace(t *testing.T) { "-ex", "continue", filepath.Join(dir, "a.exe"), } - ctx, cancel := context.WithTimeout(context.Background(), time.Minute) - defer cancel() - got, err := testenv.CommandContext(t, ctx, "gdb", args...).CombinedOutput() + cmd = testenv.Command(t, "gdb", args...) + + // Work around the GDB hang reported in https://go.dev/issue/37405. + // Sometimes (rarely), the GDB process hangs completely when the Go program + // exits, and we suspect that the bug is on the GDB side. + // + // The default Cancel function added by testenv.Command will mark the test as + // failed if it is in danger of timing out, but we want to instead mark it as + // skipped. Change the Cancel function to kill the process and merely log + // instead of failing the test. + // + // (This approach does not scale: if the test parallelism is less than or + // equal to the number of tests that run right up to the deadline, then the + // remaining parallel tests are likely to time out. But as long as it's just + // this one flaky test, it's probably fine..?) + // + // If there is no deadline set on the test at all, relying on the timeout set + // by testenv.Command will cause the test to hang indefinitely, but that's + // what “no deadline” means, after all — and it's probably the right behavior + // anyway if someone is trying to investigate and fix the GDB bug. + cmd.Cancel = func() error { + t.Logf("GDB command timed out after %v: %v", time.Since(start), cmd) + return cmd.Process.Kill() + } + + got, err := cmd.CombinedOutput() t.Logf("gdb output:\n%s", got) if err != nil { if bytes.Contains(got, []byte("internal-error: wait returned unexpected status 0x0")) {