aboutsummaryrefslogtreecommitdiffstats
path: root/vm
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-11-21 19:02:35 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-11-21 19:02:35 +0100
commitad0af9fff5f7ffbd9597e3ffb956fae3f4292b89 (patch)
tree79599e37c513c10cfe6c9f630a26e767f29a5e3d /vm
parentd4d14b030efd569a3562e5cddd751ab56afda107 (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.go47
1 files changed, 35 insertions, 12 deletions
diff --git a/vm/vm.go b/vm/vm.go
index b4933576f..24a5d55ae 100644
--- a/vm/vm.go
+++ b/vm/vm.go
@@ -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
}
}
}