diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-11-14 09:41:55 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-11-14 09:41:55 +0100 |
| commit | 7a53e7e35da7468b5a6291fa3b5e1db4bcdf402f (patch) | |
| tree | 62d7db4c53b8ab4da2fab89c25f528904d8bf517 /pkg | |
| parent | f9a8d567eb3388d0909e0d3cb6df23d345911850 (diff) | |
pkg/report: combine report data into a struct
Parse returns 5 variables now. Later we may want to add crash "priority".
Introduce Report struct that holds all report data.
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/report/akaros.go | 2 | ||||
| -rw-r--r-- | pkg/report/freebsd.go | 20 | ||||
| -rw-r--r-- | pkg/report/fuchsia.go | 2 | ||||
| -rw-r--r-- | pkg/report/linux.go | 38 | ||||
| -rw-r--r-- | pkg/report/linux_test.go | 56 | ||||
| -rw-r--r-- | pkg/report/netbsd.go | 4 | ||||
| -rw-r--r-- | pkg/report/report.go | 19 | ||||
| -rw-r--r-- | pkg/report/report_test.go | 26 | ||||
| -rw-r--r-- | pkg/report/windows.go | 2 | ||||
| -rw-r--r-- | pkg/repro/repro.go | 9 |
10 files changed, 96 insertions, 82 deletions
diff --git a/pkg/report/akaros.go b/pkg/report/akaros.go index bddc4c9de..605047fae 100644 --- a/pkg/report/akaros.go +++ b/pkg/report/akaros.go @@ -31,7 +31,7 @@ func (ctx *akaros) ContainsCrash(output []byte) bool { panic("not implemented") } -func (ctx *akaros) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { +func (ctx *akaros) Parse(output []byte) *Report { panic("not implemented") } diff --git a/pkg/report/freebsd.go b/pkg/report/freebsd.go index 976917623..70ffd2249 100644 --- a/pkg/report/freebsd.go +++ b/pkg/report/freebsd.go @@ -33,7 +33,8 @@ func (ctx *freebsd) ContainsCrash(output []byte) bool { return containsCrash(output, freebsdOopses, ctx.ignores) } -func (ctx *freebsd) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { +func (ctx *freebsd) Parse(output []byte) *Report { + rep := new(Report) var oops *oops for pos := 0; pos < len(output); { next := bytes.IndexByte(output[pos:], '\n') @@ -49,10 +50,10 @@ func (ctx *freebsd) Parse(output []byte) (desc string, text []byte, start int, e } if oops == nil { oops = oops1 - start = pos - desc = string(output[pos+match : next]) + rep.Start = pos + rep.Desc = string(output[pos+match : next]) } - end = next + rep.End = next } // Console output is indistinguishable from fuzzer output, // so we just collect everything after the oops. @@ -61,17 +62,16 @@ func (ctx *freebsd) Parse(output []byte) (desc string, text []byte, start int, e if lineEnd != 0 && output[lineEnd-1] == '\r' { lineEnd-- } - text = append(text, output[pos:lineEnd]...) - text = append(text, '\n') + rep.Text = append(rep.Text, output[pos:lineEnd]...) + rep.Text = append(rep.Text, '\n') } pos = next + 1 } if oops == nil { - return + return nil } - desc = extractDescription(output[start:], oops) - corrupted = false - return + rep.Desc = extractDescription(output[rep.Start:], oops) + return rep } func (ctx *freebsd) Symbolize(text []byte) ([]byte, error) { diff --git a/pkg/report/fuchsia.go b/pkg/report/fuchsia.go index c68291e9e..0d529a1d5 100644 --- a/pkg/report/fuchsia.go +++ b/pkg/report/fuchsia.go @@ -31,7 +31,7 @@ func (ctx *fuchsia) ContainsCrash(output []byte) bool { panic("not implemented") } -func (ctx *fuchsia) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { +func (ctx *fuchsia) Parse(output []byte) *Report { panic("not implemented") } diff --git a/pkg/report/linux.go b/pkg/report/linux.go index 9d8a90eea..8e4ed57b5 100644 --- a/pkg/report/linux.go +++ b/pkg/report/linux.go @@ -75,7 +75,8 @@ func (ctx *linux) ContainsCrash(output []byte) bool { return containsCrash(output, linuxOopses, ctx.ignores) } -func (ctx *linux) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { +func (ctx *linux) Parse(output []byte) *Report { + rep := new(Report) var oops *oops var textPrefix [][]byte textLines := 0 @@ -94,10 +95,10 @@ func (ctx *linux) Parse(output []byte) (desc string, text []byte, start int, end } if oops == nil { oops = oops1 - start = pos - desc = string(output[pos+match : next]) + rep.Start = pos + rep.Desc = string(output[pos+match : next]) } - end = next + rep.End = next } if ctx.consoleOutputRe.Match(output[pos:next]) && (!ctx.questionableRe.Match(output[pos:next]) || @@ -116,8 +117,8 @@ func (ctx *linux) Parse(output []byte) (desc string, text []byte, start int, end // Prepend 5 lines preceding start of the report, // they can contain additional info related to the report. for _, prefix := range textPrefix { - text = append(text, prefix...) - text = append(text, '\n') + rep.Text = append(rep.Text, prefix...) + rep.Text = append(rep.Text, '\n') } textPrefix = nil textLines++ @@ -139,34 +140,33 @@ func (ctx *linux) Parse(output []byte) (desc string, text []byte, start int, end skipLine = true } if !skipLine { - text = append(text, ln...) - text = append(text, '\n') + rep.Text = append(rep.Text, ln...) + rep.Text = append(rep.Text, '\n') } } } pos = next + 1 } if oops == nil { - corrupted = isCorrupted("", string(text)) - return + return nil } - desc = extractDescription(output[start:], oops) + rep.Desc = extractDescription(output[rep.Start:], oops) // Executor PIDs are not interesting. - desc = executorRe.ReplaceAllLiteralString(desc, "syz-executor") + rep.Desc = executorRe.ReplaceAllLiteralString(rep.Desc, "syz-executor") // Replace that everything looks like an address with "ADDR", // addresses in descriptions can't be good regardless of the oops regexps. - desc = addrRe.ReplaceAllLiteralString(desc, "ADDR") + rep.Desc = addrRe.ReplaceAllLiteralString(rep.Desc, "ADDR") // Replace that everything looks like a decimal number with "NUM". - desc = decNumRe.ReplaceAllLiteralString(desc, "NUM") + rep.Desc = decNumRe.ReplaceAllLiteralString(rep.Desc, "NUM") // Replace that everything looks like a file line number with "LINE". - desc = lineNumRe.ReplaceAllLiteralString(desc, ":LINE") + rep.Desc = lineNumRe.ReplaceAllLiteralString(rep.Desc, ":LINE") // Replace all raw references to runctions (e.g. "ip6_fragment+0x1052/0x2d80") // with just function name ("ip6_fragment"). Offsets and sizes are not stable. - desc = funcRe.ReplaceAllString(desc, "$1") + rep.Desc = funcRe.ReplaceAllString(rep.Desc, "$1") // CPU numbers are not interesting. - desc = cpuRe.ReplaceAllLiteralString(desc, "CPU") - corrupted = isCorrupted(desc, string(text)) - return + rep.Desc = cpuRe.ReplaceAllLiteralString(rep.Desc, "CPU") + rep.Corrupted = isCorrupted(rep.Desc, string(rep.Text)) + return rep } func (ctx *linux) Symbolize(text []byte) ([]byte, error) { diff --git a/pkg/report/linux_test.go b/pkg/report/linux_test.go index c4880c9b5..e957ad40e 100644 --- a/pkg/report/linux_test.go +++ b/pkg/report/linux_test.go @@ -794,19 +794,19 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) }, { ` [ 72.159680] BUG UNIX (Not tainted): kasan: bad access detected -`, ``, true, +`, ``, false, }, { ` [901320.960000] INFO: lockdep is turned off. -`, ``, true, +`, ``, false, }, { ` [ 72.159680] INFO: Stall ended before state dump start -`, ``, true, +`, ``, false, }, { ` [ 72.159680] WARNING: /etc/ssh/moduli does not exist, using fixed modulus -`, ``, true, +`, ``, false, }, { ` [ 1579.244514] BUG: KASAN: slab-out-of-bounds in ip6_fragment+0x1052/0x2d80 at addr ffff88004ec29b58 @@ -836,7 +836,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 92.396607] APIC base relocation is unsupported by KVM [ 95.445015] INFO: NMI handler (perf_event_nmi_handler) took too long to run: 1.356 msecs [ 95.445015] perf: interrupt took too long (3985 > 3976), lowering kernel.perf_event_max_sample_rate to 50000 -`, ``, true, +`, ``, false, }, { ` [ 92.396607] general protection fault: 0000 [#1] [ 387.811073] audit: type=1326 audit(1486238739.637:135): auid=4294967295 uid=0 gid=0 ses=4294967295 pid=10020 comm="syz-executor1" exe="/root/syz-executor1" sig=31 arch=c000003e syscall=202 compat=0 ip=0x44fad9 code=0x0 @@ -908,13 +908,13 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 37.991733] [4:SdpManagerServi: 3874] KEK_PACK[3874] __add_kek :: item ffffffc822340400 [ 38.018742] [4: system_server: 3344] logger: !@Boot_DEBUG: start networkManagement [ 38.039013] [2: kworker/2:1: 1608] Trustonic TEE: c01|TL_TZ_KEYSTORE: Starting -`, ``, true, +`, ``, false, }, { ` [ 16.761978] [syscamera][msm_companion_pll_init::526][BIN_INFO::0x0008] [ 16.762666] [syscamera][msm_companion_pll_init::544][WAFER_INFO::0xcf80] [ 16.763144] [syscamera][msm_companion_pll_init::594][BIN_INFO::0x0008][WAFER_INFO::0xcf80][voltage 0.775] -`, ``, true, +`, ``, false, }, { ` [ 72.159680] BUG: workqueue lockup - pool cpus=0 node=0 flags=0x0 nice=0 stuck for 32s! @@ -957,7 +957,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 128.793239] (ftrace buffer empty) [ 128.793242] Kernel Offset: disabled [ 129.380444] Rebooting in 86400 seconds.. -`, ``, true, +`, `kernel panic: Fatal exception`, true, }, { ` [ 238.092073] page:ffffea000712e200 count:1 mapcount:0 mapping:ffff8801c4b88c00 index:0x0 compound_mapcount: 0 @@ -981,7 +981,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 238.187128] ? __internal_add_timer+0x275/0x2d0 [ 238.191766] kasan_end_report+0x50/0x50 [ 238.195711] kasan_report+0x144/0x340 -`, ``, true, +`, `kernel panic: panic_on_warn set ...`, true, }, { ` [ 308.130685] ====================================================== @@ -1001,7 +1001,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 1722.511384] PGD 5a25067 [ 1722.511384] P4D 5a25067 [ 1722.511384] PUD 0 -`, ``, true, +`, `BUG: unable to handle kernel `, true, }, { ` [ 1722.511384] kasan: CONFIG_KASAN_INLINE enabled @@ -1021,7 +1021,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 153.634416] PGD a0ab067 PUD 21ffff067 PMD 80000000b3c001e3 [ 153.640483] Oops: 0011 [#1] SMP KASAN [ 153.644615] Modules linked in: -`, ``, true, +`, `BUG: unable to handle kernel [ 153.NUM] deprecated getsockopt IP_VLAN used by syz-executor!`, true, }, { ` [ 46.415093] syz2: link speed 10 Mbps @@ -1039,7 +1039,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) ` [ 59.534220] ================================================================== [ 59.541645] BUG: KASAN: slab-out-of-bounds in gup_huge_pmd+0x739/0x770 at addr ffff8800b46111c0 -`, ``, true, +`, `KASAN: slab-out-of-bounds in gup_huge_pmd at addr ADDR`, true, }, { ` [ 42.361487] ================================================================== @@ -1165,7 +1165,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 55.502578] Freed: [ 55.504709] PID = 4655 [ 55.507369] Memory state around the buggy address: -`, ``, true, +`, `KASAN: use-after-free Read in consume_skb`, true, }, { ` [ 322.909624] FAULT_FLAG_ALLOW_RETRY missing 30 @@ -1179,7 +1179,7 @@ r0 = ioctl$KVM_CREATE_VM(0xffffffffffffffff, 0xae01, 0x0) [ 322.914882] [<ffffffff81d91389>] dump_stack+0xc1/0x128 ** 93 printk messages dropped ** [ 322.962139] BUG: KASAN: slab-out-of-bounds in do_raw_write_lock+0x1a3/0x1d0 at addr ffff8801c464b568 ** 1987 printk messages dropped ** [ 322.975979] ffff8801c464b400: fb fb fb fb fb fb fb fb fb fb fb fb fc fc fc fc -`, ``, true, +`, `KASAN: slab-out-of-bounds in do_raw_write_lock at addr ADDR`, true, }, { ` [ 208.131930] ================================================================== @@ -1253,29 +1253,29 @@ func TestLinuxIgnores(t *testing.T) { if !reporter.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } - if desc, _, _, _, _ := reporter.Parse([]byte(log)); desc != "BUG: bug1" { - t.Fatalf("want `BUG: bug1`, found `%v`", desc) + if rep := reporter.Parse([]byte(log)); rep.Desc != "BUG: bug1" { + t.Fatalf("want `BUG: bug1`, found `%v`", rep.Desc) } if !reporter1.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } - if desc, _, _, _, _ := reporter1.Parse([]byte(log)); desc != "BUG: bug1" { - t.Fatalf("want `BUG: bug1`, found `%v`", desc) + if rep := reporter1.Parse([]byte(log)); rep.Desc != "BUG: bug1" { + t.Fatalf("want `BUG: bug1`, found `%v`", rep.Desc) } if !reporter2.ContainsCrash([]byte(log)) { t.Fatalf("no crash") } - if desc, _, _, _, _ := reporter2.Parse([]byte(log)); desc != "BUG: bug2" { - t.Fatalf("want `BUG: bug2`, found `%v`", desc) + if rep := reporter2.Parse([]byte(log)); rep.Desc != "BUG: bug2" { + t.Fatalf("want `BUG: bug2`, found `%v`", rep.Desc) } if reporter3.ContainsCrash([]byte(log)) { t.Fatalf("found crash, should be ignored") } - if desc, _, _, _, _ := reporter3.Parse([]byte(log)); desc != "" { - t.Fatalf("found `%v`, should be ignored", desc) + if rep := reporter3.Parse([]byte(log)); rep != nil { + t.Fatalf("found `%v`, should be ignored", rep.Desc) } } @@ -1328,11 +1328,11 @@ Read of size 4 by task syz-executor2/5764 t.Fatal(err) } for log, text0 := range tests { - if desc, text, _, _, _ := reporter.Parse([]byte(log)); string(text) != text0 { + if rep := reporter.Parse([]byte(log)); string(rep.Text) != text0 { t.Logf("log:\n%s", log) t.Logf("want text:\n%s", text0) - t.Logf("got text:\n%s", text) - t.Fatalf("bad text, desc: '%v'", desc) + t.Logf("got text:\n%s", rep.Text) + t.Fatalf("bad text, desc: '%v'", rep.Desc) } } } @@ -1496,10 +1496,10 @@ func TestLinuxParseReport(t *testing.T) { } for i, test := range parseReportTests { t.Run(fmt.Sprint(i), func(t *testing.T) { - _, text, _, _, _ := reporter.Parse([]byte(test.in)) - if test.out != string(text) { + rep := reporter.Parse([]byte(test.in)) + if test.out != string(rep.Text) { t.Logf("expect:\n%v", test.out) - t.Logf("got:\n%v", string(text)) + t.Logf("got:\n%v", string(rep.Text)) t.Fail() } }) diff --git a/pkg/report/netbsd.go b/pkg/report/netbsd.go index 4a43046c7..f5aab3faf 100644 --- a/pkg/report/netbsd.go +++ b/pkg/report/netbsd.go @@ -32,8 +32,8 @@ func (ctx *netbsd) ContainsCrash(output []byte) bool { return false } -func (ctx *netbsd) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { - return "", nil, 0, 0, false +func (ctx *netbsd) Parse(output []byte) *Report { + return nil } func (ctx *netbsd) Symbolize(text []byte) ([]byte, error) { diff --git a/pkg/report/report.go b/pkg/report/report.go index 2738e4070..efc1623bd 100644 --- a/pkg/report/report.go +++ b/pkg/report/report.go @@ -19,11 +19,8 @@ type Reporter interface { ContainsCrash(output []byte) bool // Parse extracts information about oops from console output. - // Desc contains a representative description of the first oops (empty if no oops found), - // text contains whole oops text, - // start and end denote region of output with oops message(s), - // corrupted indicates whether the report is truncated of corrupted in some other way. - Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) + // Returns nil if no oops found. + Parse(output []byte) *Report Symbolize(text []byte) ([]byte, error) @@ -32,6 +29,18 @@ type Reporter interface { GetMaintainers(file string) ([]string, error) } +type Report struct { + // Desc contains a representative description of the first oops. + Desc string + // Text contains whole oops text. + Text []byte + // Start and End denote region of output with oops message(s). + Start int + End int + // Corrupted indicates whether the report is truncated of corrupted in some other way. + Corrupted bool +} + // NewReporter creates reporter for the specified OS: // kernelSrc: path to kernel sources directory // kernelObj: path to kernel build directory (can be empty for in-tree build) diff --git a/pkg/report/report_test.go b/pkg/report/report_test.go index b4aa9a215..6802d0772 100644 --- a/pkg/report/report_test.go +++ b/pkg/report/report_test.go @@ -60,17 +60,7 @@ func testParse(t *testing.T, os string, tests []ParseTest) { tests = append(tests, test) } for _, test := range tests { - desc, _, _, _, corrupted := reporter.Parse([]byte(test.Log)) - if corrupted && !test.Corrupted { - t.Fatalf("incorrectly marked report as corrupted: '%v'\n%v", desc, test.Log) - } - if !corrupted && test.Corrupted { - t.Fatalf("failed to mark report as corrupted: '%v'\n%v", desc, test.Log) - } - if corrupted && test.Desc == "" { - // Allow ignoring crash description for corrupted reports - continue - } + rep := reporter.Parse([]byte(test.Log)) containsCrash := reporter.ContainsCrash([]byte(test.Log)) expectCrash := (test.Desc != "") if expectCrash && !containsCrash { @@ -79,6 +69,14 @@ func testParse(t *testing.T, os string, tests []ParseTest) { if !expectCrash && containsCrash { t.Fatalf("ContainsCrash found unexpected crash:\n%v", test.Log) } + if rep != nil && rep.Desc == "" { + t.Fatalf("found crash, but title is empty '%v' in:\n%v", test.Desc, test.Log) + } + desc, corrupted := "", false + if rep != nil { + desc = rep.Desc + corrupted = rep.Corrupted + } if desc == "" && test.Desc != "" { t.Fatalf("did not find crash message '%v' in:\n%v", test.Desc, test.Log) } @@ -88,5 +86,11 @@ func testParse(t *testing.T, os string, tests []ParseTest) { if desc != test.Desc { t.Fatalf("extracted bad crash message:\n%+q\nwant:\n%+q", desc, test.Desc) } + if corrupted && !test.Corrupted { + t.Fatalf("incorrectly marked report as corrupted: '%v'\n%v", desc, test.Log) + } + if !corrupted && test.Corrupted { + t.Fatalf("failed to mark report as corrupted: '%v'\n%v", desc, test.Log) + } } } diff --git a/pkg/report/windows.go b/pkg/report/windows.go index cb62cf181..17e1f1bc7 100644 --- a/pkg/report/windows.go +++ b/pkg/report/windows.go @@ -31,7 +31,7 @@ func (ctx *windows) ContainsCrash(output []byte) bool { panic("not implemented") } -func (ctx *windows) Parse(output []byte) (desc string, text []byte, start int, end int, corrupted bool) { +func (ctx *windows) Parse(output []byte) *Report { panic("not implemented") } diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index 699f0d7c3..b6b6a908e 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -74,10 +74,11 @@ func Run(crashLog []byte, cfg *mgrconfig.Config, reporter report.Reporter, vmPoo if len(entries) == 0 { return nil, fmt.Errorf("crash log does not contain any programs") } - crashDesc, _, crashStart, _, _ := reporter.Parse(crashLog) - if crashDesc == "" { - crashStart = len(crashLog) // assuming VM hanged - crashDesc = "hang" + crashStart := len(crashLog) // assuming VM hanged + crashDesc := "hang" + if rep := reporter.Parse(crashLog); rep != nil { + crashStart = rep.Start + crashDesc = rep.Desc } ctx := &context{ |
