diff --git a/pkg/instance/instance.go b/pkg/instance/instance.go index d8883857..39de0201 100644 --- a/pkg/instance/instance.go +++ b/pkg/instance/instance.go @@ -6,7 +6,6 @@ package instance import ( - "bytes" "encoding/json" "fmt" "net" @@ -245,11 +244,7 @@ func (inst *inst) test() error { rep := inst.reporter.Parse(testErr.Output) if rep != nil && rep.Type == report.UnexpectedReboot { // Avoid detecting any boot crash as "unexpected kernel reboot". - output := testErr.Output[rep.EndPos:] - if pos := bytes.IndexByte(testErr.Output[rep.StartPos:], '\n'); pos != -1 { - output = testErr.Output[rep.StartPos+pos:] - } - rep = inst.reporter.Parse(output) + rep = inst.reporter.Parse(testErr.Output[rep.SkipPos:]) } if rep == nil { rep = &report.Report{ diff --git a/pkg/report/fuzz.go b/pkg/report/fuzz.go index 82b42849..02f02c4d 100644 --- a/pkg/report/fuzz.go +++ b/pkg/report/fuzz.go @@ -11,7 +11,7 @@ import ( func Fuzz(data []byte) int { res := 0 - for _, reporter := range fuzzReporters { + for os, reporter := range fuzzReporters { typ := reporter.(*reporterWrapper).typ containsCrash := reporter.ContainsCrash(data) rep := reporter.Parse(data) @@ -32,18 +32,41 @@ func Fuzz(data []byte) int { if len(rep.Output) == 0 { panic(fmt.Sprintf("%v: len(Output) == 0", typ)) } + switch os { + case "openbsd", "netbsd", "fuchsia": + // openbsd/netbsd has Start/End/SkipPos set incorrectly due to messing with /r/n. + // fuchsia because it symbolizes before parsing. + continue + } if rep.StartPos != 0 && rep.EndPos != 0 && rep.StartPos >= rep.EndPos { - panic(fmt.Sprintf("%v: StartPos=%v >= EndPos=%v", typ, rep.StartPos, rep.EndPos)) + panic(fmt.Sprintf("%v: bad StartPos\nStartPos=%v >= EndPos=%v", + typ, rep.StartPos, rep.EndPos)) } if rep.EndPos > len(rep.Output) { - panic(fmt.Sprintf("%v: EndPos=%v > len(Output)=%v", typ, rep.EndPos, len(rep.Output))) + panic(fmt.Sprintf("%v: bad EndPos\nEndPos=%v > len(Output)=%v", + typ, rep.EndPos, len(rep.Output))) + } + if rep.SkipPos <= rep.StartPos || rep.SkipPos > rep.EndPos { + panic(fmt.Sprintf("%v: bad SkipPos\nSkipPos=%v: StartPos=%v EndPos=%v", + typ, rep.SkipPos, rep.StartPos, rep.EndPos)) + } + // If we parse from StartPos, we must find the same report. + rep1 := reporter.Parse(data[rep.StartPos:]) + if rep1 == nil || rep1.Title != rep.Title || rep1.StartPos != 0 { + title, startPos := "", -1 + if rep1 != nil { + title, startPos = rep1.Title, rep1.StartPos + } + panic(fmt.Sprintf("%v: did not find the same reports at StartPos\n"+ + "StartPos=%v/%v\nTitle0=%q\nTitle1=%q", + typ, rep.StartPos, startPos, rep.Title, title)) } } return res } -var fuzzReporters = func() []Reporter { - var reporters []Reporter +var fuzzReporters = func() map[string]Reporter { + reporters := make(map[string]Reporter) for os := range ctors { if os == "windows" { continue @@ -59,7 +82,7 @@ var fuzzReporters = func() []Reporter { if _, ok := reporter.(*stub); ok { continue } - reporters = append(reporters, reporter) + reporters[os] = reporter } return reporters }() diff --git a/pkg/report/report.go b/pkg/report/report.go index 673407f9..e6d13b93 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -42,6 +42,8 @@ type Report struct { // StartPos/EndPos denote region of output with oops message(s). StartPos int EndPos int + // SkipPos is position in output where parsing for the next report should start. + SkipPos int // Suppressed indicates whether the report should not be reported to user. Suppressed bool // Corrupted indicates whether the report is truncated of corrupted in some other way. @@ -184,6 +186,15 @@ func (wrap *reporterWrapper) Parse(output []byte) *Report { if pos := bytes.Index(rep.Report, []byte(VMDiagnosisStart)); pos != -1 { rep.Report = rep.Report[:pos] } + rep.SkipPos = len(output) + if pos := bytes.IndexByte(output[rep.StartPos:], '\n'); pos != -1 { + rep.SkipPos = rep.StartPos + pos + } + if rep.EndPos < rep.SkipPos { + // This generally should not happen. + // But openbsd does some hacks with /r/n which may lead to off-by-one EndPos. + rep.EndPos = rep.SkipPos + } return rep } diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go index aebcb45f..39cd0deb 100644 --- a/pkg/report/report_test.go +++ b/pkg/report/report_test.go @@ -186,22 +186,10 @@ func testParseImpl(t *testing.T, reporter Reporter, test *ParseTest) { if rep == nil { return } - checkReport(t, rep, test) - if rep.StartPos != 0 { - // If we parse from StartPos, we must find the same report. - rep1 := reporter.Parse(test.Log[rep.StartPos:]) - if rep1 == nil || rep1.Title != rep.Title { - t.Fatalf("did not find the same report from rep.StartPos=%v", rep.StartPos) - } - // If we parse from EndPos, we must not find the same report. - rep2 := reporter.Parse(test.Log[rep.EndPos:]) - if rep2 != nil && rep2.Title == rep.Title { - t.Fatalf("found the same report after rep.EndPos=%v", rep.EndPos) - } - } + checkReport(t, reporter, rep, test) } -func checkReport(t *testing.T, rep *Report, test *ParseTest) { +func checkReport(t *testing.T, reporter Reporter, rep *Report, test *ParseTest) { if test.HasReport && !bytes.Equal(rep.Report, test.Report) { t.Fatalf("extracted wrong report:\n%s\nwant:\n%s", rep.Report, test.Report) } @@ -214,6 +202,9 @@ func checkReport(t *testing.T, rep *Report, test *ParseTest) { if rep.EndPos > len(rep.Output) { t.Fatalf("EndPos=%v > len(Output)=%v", rep.EndPos, len(rep.Output)) } + if rep.SkipPos <= rep.StartPos || rep.SkipPos > rep.EndPos { + t.Fatalf("bad SkipPos=%v: StartPos=%v EndPos=%v", rep.SkipPos, rep.StartPos, rep.EndPos) + } if test.StartLine != "" { if test.EndLine == "" { test.EndLine = test.StartLine @@ -226,6 +217,18 @@ func checkReport(t *testing.T, rep *Report, test *ParseTest) { string(test.Log[rep.StartPos:rep.EndPos])) } } + if rep.StartPos != 0 { + // If we parse from StartPos, we must find the same report. + rep1 := reporter.Parse(test.Log[rep.StartPos:]) + if rep1 == nil || rep1.Title != rep.Title || rep1.StartPos != 0 { + t.Fatalf("did not find the same report from rep.StartPos=%v", rep.StartPos) + } + // If we parse from EndPos, we must not find the same report. + rep2 := reporter.Parse(test.Log[rep.EndPos:]) + if rep2 != nil && rep2.Title == rep.Title { + t.Fatalf("found the same report after rep.EndPos=%v", rep.EndPos) + } + } } func updateReportTest(t *testing.T, test *ParseTest, title string, corrupted, suppressed bool,