misc/cgo/testsanitizers: terminate commands with SIGQUIT if hung

If the test hangs due to a deadlock in a subprocess, we want a
goroutine dump of that process to figure out the nature of the
deadlock. SIGQUIT causes the Go runtime to produce exactly
such a dump (unless the runtime itself is badly deadlocked).

For #52998.

Change-Id: Id9b3ba89d8f705e14f6cd789353fc2b7f4774ad3
Reviewed-on: https://go-review.googlesource.com/c/go/+/407954
Reviewed-by: Ian Lance Taylor <iant@google.com>
Run-TryBot: Bryan Mills <bcmills@google.com>
Auto-Submit: Bryan Mills <bcmills@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
Bryan C. Mills 2022-05-23 16:27:13 -04:00 committed by Gopher Robot
parent 74f0ccb68b
commit 715ba65563

View File

@ -20,6 +20,7 @@ import (
"sync"
"syscall"
"testing"
"time"
"unicode"
)
@ -90,9 +91,26 @@ func replaceEnv(cmd *exec.Cmd, key, value string) {
// mustRun executes t and fails cmd with a well-formatted message if it fails.
func mustRun(t *testing.T, cmd *exec.Cmd) {
t.Helper()
out, err := cmd.CombinedOutput()
out := new(strings.Builder)
cmd.Stdout = out
cmd.Stderr = out
err := cmd.Start()
if err != nil {
t.Fatalf("%#q exited with %v\n%s", strings.Join(cmd.Args, " "), err, out)
t.Fatalf("%v: %v", cmd, err)
}
if deadline, ok := t.Deadline(); ok {
timeout := time.Until(deadline)
timeout -= timeout / 10 // Leave 10% headroom for logging and cleanup.
timer := time.AfterFunc(timeout, func() {
cmd.Process.Signal(syscall.SIGQUIT)
})
defer timer.Stop()
}
if err := cmd.Wait(); err != nil {
t.Fatalf("%v exited with %v\n%s", cmd, err, out)
}
}