diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-11-21 19:02:35 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-11-21 19:02:35 +0100 |
| commit | ad0af9fff5f7ffbd9597e3ffb956fae3f4292b89 (patch) | |
| tree | 79599e37c513c10cfe6c9f630a26e767f29a5e3d /vm | |
| parent | d4d14b030efd569a3562e5cddd751ab56afda107 (diff) | |
vm: return Report from MonitorExecution
This allows callers to get access to Report.Corrupted.
Better than adding 6-th return value and will allow
to pipe other report properties if necessary.
Diffstat (limited to 'vm')
| -rw-r--r-- | vm/vm.go | 47 |
1 files changed, 35 insertions, 12 deletions
@@ -96,8 +96,14 @@ func (inst *Instance) Close() { os.RemoveAll(inst.workdir) } -func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Reporter) ( - title string, report, output []byte, crashed, timedout bool) { +// MonitorExecution monitors execution of a program running inside of a VM. +// It detects kernel oopses in output, lost connections, hangs, etc. +// outc/errc is what vm.Instance.Run returns, reporter parses kernel output for oopses. +// If canExit is false and the program exits, it is treated as an error. +// Returns crash report and raw output around the crash, or nil if no error happens. +func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Reporter, canExit bool) ( + rep *report.Report, output []byte) { + //title string, report, output []byte, crashed, timedout bool) { waitForOutput := func() { timer := time.NewTimer(10 * time.Second).C for { @@ -118,14 +124,23 @@ func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Rep beforeContext = 1024 << 10 afterContext = 128 << 10 ) - extractError := func(defaultError string) (string, []byte, []byte, bool, bool) { + extractError := func(defaultError string) (*report.Report, []byte) { // Give it some time to finish writing the error message. waitForOutput() if bytes.Contains(output, []byte("SYZ-FUZZER: PREEMPTED")) { - return "preempted", nil, nil, false, true + return nil, nil } if !reporter.ContainsCrash(output[matchPos:]) { - return defaultError, nil, output, defaultError != "", false + if defaultError == "" { + if canExit { + return nil, nil + } + defaultError = "lost connection to test machine" + } + rep := &report.Report{ + Title: defaultError, + } + return rep, output } rep := reporter.Parse(output[matchPos:]) if rep == nil { @@ -139,7 +154,7 @@ func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Rep if end > len(output) { end = len(output) } - return rep.Title, rep.Report, output[start:end], true, false + return rep, output[start:end] } lastExecuteTime := time.Now() @@ -159,7 +174,7 @@ func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Rep // but wait for kernel output in case there is some delayed oops. return extractError("") case TimeoutErr: - return err.Error(), nil, nil, false, true + return nil, nil default: // Note: connection lost can race with a kernel oops message. // In such case we want to return the kernel oops. @@ -167,10 +182,12 @@ func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Rep } case out := <-outc: output = append(output, out...) - if bytes.Index(output[matchPos:], []byte("executing program")) != -1 { // syz-fuzzer output + // syz-fuzzer output + if bytes.Index(output[matchPos:], []byte("executing program")) != -1 { lastExecuteTime = time.Now() } - if bytes.Index(output[matchPos:], []byte("executed programs:")) != -1 { // syz-execprog output + // syz-execprog output + if bytes.Index(output[matchPos:], []byte("executed programs:")) != -1 { lastExecuteTime = time.Now() } if reporter.ContainsCrash(output[matchPos:]) { @@ -189,13 +206,19 @@ func MonitorExecution(outc <-chan []byte, errc <-chan error, reporter report.Rep // We intentionally produce the same title as no output at all, // because frequently it's the same condition. if time.Since(lastExecuteTime) > 3*time.Minute { - return "no output from test machine", nil, output, true, false + rep := &report.Report{ + Title: "no output from test machine", + } + return rep, output } case <-ticker.C: tickerFired = true - return "no output from test machine", nil, output, true, false + rep := &report.Report{ + Title: "no output from test machine", + } + return rep, output case <-Shutdown: - return "", nil, nil, false, false + return nil, nil } } } |
