mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.fuzz] internal/fuzz: handle SIGINT races gracefully
A worker process may be terminated by SIGINT if it doesn't install the signal handler before SIGINT is delivered. That's likely when TestMain or the fuzz target setup take a long time. The coordinator now ignores these errors. Also, when testdeps.TestDeps.CoordinateFuzzing and RunFuzzWorker return, they will send a value on the chan passed to signal.Notify instead of closing it. This should have been obvious in hindsight, but the signal handler could still send a value on that channel after those functions return but before the process exits. Change-Id: Iea2589115f1f9bb7415bb5e7911defee423e642e Reviewed-on: https://go-review.googlesource.com/c/go/+/284292 Trust: Jay Conrod <jayconrod@google.com> Reviewed-by: Katie Hockman <katie@golang.org>
This commit is contained in:
parent
d45df5de32
commit
8e0584c327
5 changed files with 41 additions and 8 deletions
|
|
@ -73,3 +73,14 @@ func getWorkerComm() (comm workerComm, err error) {
|
|||
}
|
||||
return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, mem: mem}, nil
|
||||
}
|
||||
|
||||
// isInterruptError returns whether an error was returned by a process that
|
||||
// was terminated by an interrupt signal (SIGINT).
|
||||
func isInterruptError(err error) bool {
|
||||
exitErr, ok := err.(*exec.ExitError)
|
||||
if !ok || exitErr.ExitCode() >= 0 {
|
||||
return false
|
||||
}
|
||||
status := exitErr.Sys().(syscall.WaitStatus)
|
||||
return status.Signal() == syscall.SIGINT
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,3 +29,7 @@ func setWorkerComm(cmd *exec.Cmd, comm workerComm) {
|
|||
func getWorkerComm() (comm workerComm, err error) {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
||||
func isInterruptError(err error) bool {
|
||||
panic("not implemented")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -131,3 +131,8 @@ func getWorkerComm() (comm workerComm, err error) {
|
|||
|
||||
return workerComm{fuzzIn: fuzzIn, fuzzOut: fuzzOut, mem: mem}, nil
|
||||
}
|
||||
|
||||
func isInterruptError(err error) bool {
|
||||
// TODO(jayconrod): implement
|
||||
return false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -80,19 +80,32 @@ func (w *worker) runFuzzing() error {
|
|||
select {
|
||||
case <-w.coordinator.doneC:
|
||||
// All workers were told to stop.
|
||||
return w.stop()
|
||||
err := w.stop()
|
||||
if isInterruptError(err) {
|
||||
// Worker interrupted by SIGINT. This can happen if the worker receives
|
||||
// SIGINT before installing the signal handler. That's likely if
|
||||
// TestMain or the fuzz target setup takes a long time.
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
|
||||
case <-w.termC:
|
||||
// Worker process terminated unexpectedly, so inform the coordinator
|
||||
// that a crash occurred.
|
||||
// Worker process terminated unexpectedly.
|
||||
if isInterruptError(w.waitErr) {
|
||||
// Worker interrupted by SIGINT. See comment in doneC case.
|
||||
w.stop()
|
||||
return nil
|
||||
}
|
||||
|
||||
// Unexpected termination. Inform the coordinator about the crash.
|
||||
// TODO(jayconrod,katiehockman): if -keepfuzzing, restart worker.
|
||||
value := w.mem.valueCopy()
|
||||
message := fmt.Sprintf("fuzzing process terminated unexpectedly: %v", w.waitErr)
|
||||
crasher := crasherEntry{
|
||||
corpusEntry: corpusEntry{b: value},
|
||||
errMsg: "fuzzing process crashed unexpectedly",
|
||||
errMsg: message,
|
||||
}
|
||||
w.coordinator.crasherC <- crasher
|
||||
|
||||
// TODO(jayconrod,katiehockman): if -keepfuzzing, restart worker.
|
||||
err := w.stop()
|
||||
if err == nil {
|
||||
err = fmt.Errorf("worker exited unexpectedly")
|
||||
|
|
|
|||
|
|
@ -146,7 +146,7 @@ func (TestDeps) CoordinateFuzzing(timeout time.Duration, parallel int, seed [][]
|
|||
<-interruptC
|
||||
cancel()
|
||||
}()
|
||||
defer close(interruptC)
|
||||
defer func() { interruptC <- os.Interrupt }()
|
||||
|
||||
err := fuzz.CoordinateFuzzing(ctx, parallel, seed, corpusDir, cacheDir)
|
||||
if err == ctx.Err() {
|
||||
|
|
@ -169,7 +169,7 @@ func (TestDeps) RunFuzzWorker(fn func([]byte) error) error {
|
|||
<-interruptC
|
||||
cancel()
|
||||
}()
|
||||
defer close(interruptC)
|
||||
defer func() { interruptC <- os.Interrupt }()
|
||||
|
||||
err := fuzz.RunFuzzWorker(ctx, fn)
|
||||
if err == ctx.Err() {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue