aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-11-29 15:19:29 +0100
committerDmitry Vyukov <dvyukov@google.com>2016-11-29 15:19:29 +0100
commit4278c63e64234425ea1655e3207d85b627fc17f2 (patch)
tree64fc9ba6841b20a01b5ef44aae3688792129ed71
parenteac6d72f0eab063e5aaa5ca38f4347c2d6438885 (diff)
ipc: improve handling of executor failures
1. Logical executor failures were not handled in waitServing. 2. Fuzzer did not distinguish temporal errors and logical errors and always waited for 10 errors before crashing. Fix that.
-rw-r--r--ipc/ipc.go27
-rw-r--r--syz-fuzzer/fuzzer.go2
2 files changed, 27 insertions, 2 deletions
diff --git a/ipc/ipc.go b/ipc/ipc.go
index 36cee04c5..dbb2a878d 100644
--- a/ipc/ipc.go
+++ b/ipc/ipc.go
@@ -59,6 +59,14 @@ var (
flagTimeout = flag.Duration("timeout", 1*time.Minute, "execution timeout")
)
+// ExecutorFailure is returned from MakeEnv or from env.Exec when executor terminates by calling fail function.
+// This is considered a logical error (a failed assert).
+type ExecutorFailure string
+
+func (err ExecutorFailure) Error() string {
+ return string(err)
+}
+
func DefaultFlags() (uint64, time.Duration, error) {
var flags uint64
if *flagThreaded {
@@ -403,6 +411,8 @@ func makeCommand(bin []string, timeout time.Duration, flags uint64, inFile *os.F
return nil, fmt.Errorf("failed to start executor binary: %v", err)
}
c.cmd = cmd
+ wp.Close()
+ inwp.Close()
if err := c.waitServing(); err != nil {
return nil, err
}
@@ -439,6 +449,21 @@ func (c *command) waitServing() error {
select {
case err := <-read:
timeout.Stop()
+ if err != nil {
+ c.kill()
+ output := <-c.readDone
+ err = fmt.Errorf("executor is not serving: %v\n%s", err, output)
+ c.cmd.Wait()
+ if c.cmd.ProcessState != nil {
+ sys := c.cmd.ProcessState.Sys()
+ if ws, ok := sys.(syscall.WaitStatus); ok {
+ // Magic values returned by executor.
+ if ws.ExitStatus() == 67 {
+ err = ExecutorFailure(fmt.Sprintf("executor is not serving:\n%s", output))
+ }
+ }
+ }
+ }
return err
case <-timeout.C:
return fmt.Errorf("executor is not serving")
@@ -488,7 +513,7 @@ func (c *command) exec() (output []byte, failed, hanged, restart bool, err0 erro
if ws, ok := sys.(syscall.WaitStatus); ok {
// Magic values returned by executor.
if ws.ExitStatus() == 67 {
- err0 = fmt.Errorf("executor failed: %s", output)
+ err0 = ExecutorFailure(fmt.Sprintf("executor failed: %s", output))
}
if ws.ExitStatus() == 68 {
failed = true
diff --git a/syz-fuzzer/fuzzer.go b/syz-fuzzer/fuzzer.go
index 42e2768e1..b1b8fd426 100644
--- a/syz-fuzzer/fuzzer.go
+++ b/syz-fuzzer/fuzzer.go
@@ -521,7 +521,7 @@ retry:
return make([]cover.Cover, len(p.Calls))
}
if err != nil {
- if try > 10 {
+ if _, ok := err.(ipc.ExecutorFailure); ok || try > 10 {
panic(err)
}
try++