From 56cc113a8ea223321811dcbe8de975e081f5f5b2 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Wed, 17 Jan 2018 21:50:57 +0100 Subject: dashboard/app: improve report format - show kernel repo alias - show commit title/date - say how many times the crash happened/where - some minor tweaks Fixes #468 --- dashboard/app/email_test.go | 65 +++++++++++++++--------- dashboard/app/entities.go | 17 +++++++ dashboard/app/index.yaml | 7 +++ dashboard/app/jobs.go | 41 ++++++++------- dashboard/app/jobs_test.go | 20 +++++--- dashboard/app/mail_bug.txt | 18 ++++--- dashboard/app/mail_test_result.txt | 6 ++- dashboard/app/reporting.go | 22 ++++++++ dashboard/app/reporting_email.go | 100 ++++++++++++++++++++++++------------- dashboard/app/reporting_test.go | 6 +++ dashboard/dashapi/dashapi.go | 2 + 11 files changed, 212 insertions(+), 92 deletions(-) diff --git a/dashboard/app/email_test.go b/dashboard/app/email_test.go index 3de96639c..d6f69a5a8 100644 --- a/dashboard/app/email_test.go +++ b/dashboard/app/email_test.go @@ -49,12 +49,14 @@ func TestEmailReport(t *testing.T) { c.expectEQ(msg.Attachments[1].Data, crash.Log) body := fmt.Sprintf(`Hello, -syzkaller hit the following crash on kernel_commit1 -repo1/branch1 +syzbot hit the following crash on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 -.config is attached +.config is attached. Raw console output is attached. -Unfortunately, I don't have any reproducer for this bug yet. +Unfortunately, I don't have any reproducer for this crash yet. CC: [bar@foo.com foo@bar.com] IMPORTANT: if you fix the bug, please add the following tag to the commit: @@ -153,13 +155,16 @@ For more options, visit https://groups.google.com/d/optout. c.expectEQ(msg.Attachments[2].Name, "repro.syz.txt") c.expectEQ(msg.Attachments[2].Data, syzRepro) c.expectEQ(msg.Headers["In-Reply-To"], []string{"<1234>"}) - body := fmt.Sprintf(`syzkaller has found reproducer for the following crash on kernel_commit1 -repo1/branch1 + body := fmt.Sprintf(`syzbot has found reproducer for the following crash on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 -.config is attached +.config is attached. Raw console output is attached. syzkaller reproducer is attached. See https://goo.gl/kgGztJ -for information about syzkaller reproducers +for information about syzkaller reproducers. +So far this crash happened 2 times on repo1/branch1. CC: [bar@foo.com foo@bar.com] IMPORTANT: if you fix the bug, please add the following tag to the commit: @@ -202,13 +207,16 @@ report1 c.expectEQ(msg.Attachments[2].Data, syzRepro) body := fmt.Sprintf(`Hello, -syzkaller hit the following crash on kernel_commit1 -repo1/branch1 +syzbot hit the following crash on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 -.config is attached +.config is attached. Raw console output is attached. syzkaller reproducer is attached. See https://goo.gl/kgGztJ -for information about syzkaller reproducers +for information about syzkaller reproducers. +So far this crash happened 2 times on repo1/branch1. IMPORTANT: if you fix the bug, please add the following tag to the commit: @@ -258,6 +266,9 @@ Content-Type: text/plain c.expectOK(c.POST("/_ah/mail/", incoming3)) // Now upload a C reproducer. + build2 := testBuild(2) + c.expectOK(c.API(client2, key2, "upload_build", build2, nil)) + crash.BuildID = build2.ID crash.ReproC = []byte("int main() {}") crash.Maintainers = []string{"\"qux\" "} c.expectOK(c.API(client2, key2, "report_crash", crash, nil)) @@ -276,21 +287,24 @@ Content-Type: text/plain c.expectEQ(msg.Subject, crash.Title) c.expectEQ(len(msg.Attachments), 4) c.expectEQ(msg.Attachments[0].Name, "config.txt") - c.expectEQ(msg.Attachments[0].Data, build.KernelConfig) + c.expectEQ(msg.Attachments[0].Data, build2.KernelConfig) c.expectEQ(msg.Attachments[1].Name, "raw.log.txt") c.expectEQ(msg.Attachments[1].Data, crash.Log) c.expectEQ(msg.Attachments[2].Name, "repro.syz.txt") c.expectEQ(msg.Attachments[2].Data, syzRepro) c.expectEQ(msg.Attachments[3].Name, "repro.c.txt") c.expectEQ(msg.Attachments[3].Data, crash.ReproC) - body := fmt.Sprintf(`syzkaller has found reproducer for the following crash on kernel_commit1 -repo1/branch1 -compiler: compiler1 -.config is attached + body := fmt.Sprintf(`syzbot has found reproducer for the following crash on repo2/branch2 commit +kernel_commit2 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title2 + +compiler: compiler2 +.config is attached. Raw console output is attached. -C reproducer is attached +C reproducer is attached. syzkaller reproducer is attached. See https://goo.gl/kgGztJ -for information about syzkaller reproducers +for information about syzkaller reproducers. +So far this crash happened 3 times on repo1/branch1, repo2/branch2. IMPORTANT: if you fix the bug, please add the following tag to the commit: @@ -345,10 +359,15 @@ unknown command "bad-command" c.expectEQ(len(builderPollResp.PendingCommits), 1) c.expectEQ(builderPollResp.PendingCommits[0], "some: commit title") - build2 := testBuild(2) - build2.Manager = build.Manager - build2.Commits = []string{"some: commit title"} - c.expectOK(c.API(client2, key2, "upload_build", build2, nil)) + build3 := testBuild(3) + build3.Manager = build.Manager + build3.Commits = []string{"some: commit title"} + c.expectOK(c.API(client2, key2, "upload_build", build3, nil)) + + build4 := testBuild(4) + build4.Manager = build2.Manager + build4.Commits = []string{"some: commit title"} + c.expectOK(c.API(client2, key2, "upload_build", build4, nil)) // New crash must produce new bug in the first reporting. c.expectOK(c.API(client2, key2, "report_crash", crash, nil)) diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go index c79e3ddc9..8036eb5e4 100644 --- a/dashboard/app/entities.go +++ b/dashboard/app/entities.go @@ -270,6 +270,23 @@ func loadBuild(c context.Context, ns, id string) (*Build, error) { return build, nil } +func lastManagerBuild(c context.Context, ns, manager string) (*Build, error) { + var builds []*Build + _, err := datastore.NewQuery("Build"). + Filter("Namespace=", ns). + Filter("Manager=", manager). + Order("-Time"). + Limit(1). + GetAll(c, &builds) + if err != nil { + return nil, fmt.Errorf("failed to fetch manager build: %v", err) + } + if len(builds) == 0 { + return nil, fmt.Errorf("failed to fetch manager build: no builds") + } + return builds[0], nil +} + func (bug *Bug) displayTitle() string { if bug.Seq == 0 { return bug.Title diff --git a/dashboard/app/index.yaml b/dashboard/app/index.yaml index d0f14cfc8..761bd0ce4 100644 --- a/dashboard/app/index.yaml +++ b/dashboard/app/index.yaml @@ -27,6 +27,13 @@ indexes: - name: Namespace - name: Manager +- kind: Build + properties: + - name: Namespace + - name: Manager + - name: Time + direction: desc + - kind: Crash ancestor: yes properties: diff --git a/dashboard/app/jobs.go b/dashboard/app/jobs.go index ff5f127cb..4574a333e 100644 --- a/dashboard/app/jobs.go +++ b/dashboard/app/jobs.go @@ -346,25 +346,28 @@ func createBugReportForJob(c context.Context, job *Job, jobKey *datastore.Key, c return nil, fmt.Errorf("job bug has no reporting %q", job.Reporting) } rep := &dashapi.BugReport{ - Namespace: job.Namespace, - Config: reportingConfig, - ID: bugReporting.ID, - JobID: extJobID(jobKey), - ExtID: job.ExtID, - Title: bug.displayTitle(), - Log: crashLog, - Report: report, - OS: build.OS, - Arch: build.Arch, - VMArch: build.VMArch, - CompilerID: build.CompilerID, - KernelRepo: build.KernelRepo, - KernelBranch: build.KernelBranch, - KernelCommit: build.KernelCommit, - KernelConfig: kernelConfig, - CrashTitle: job.CrashTitle, - Error: jobError, - Patch: patch, + Namespace: job.Namespace, + Config: reportingConfig, + ID: bugReporting.ID, + JobID: extJobID(jobKey), + ExtID: job.ExtID, + Title: bug.displayTitle(), + Log: crashLog, + Report: report, + OS: build.OS, + Arch: build.Arch, + VMArch: build.VMArch, + CompilerID: build.CompilerID, + KernelRepo: build.KernelRepo, + KernelRepoAlias: kernelRepoInfo(build).Alias, + KernelBranch: build.KernelBranch, + KernelCommit: build.KernelCommit, + KernelCommitTitle: build.KernelCommitTitle, + KernelCommitDate: build.KernelCommitDate, + KernelConfig: kernelConfig, + CrashTitle: job.CrashTitle, + Error: jobError, + Patch: patch, } if bugReporting.CC != "" { rep.CC = strings.Split(bugReporting.CC, "|") diff --git a/dashboard/app/jobs_test.go b/dashboard/app/jobs_test.go index 77eb594e4..cb7d0cd9a 100644 --- a/dashboard/app/jobs_test.go +++ b/dashboard/app/jobs_test.go @@ -52,7 +52,7 @@ func TestJob(t *testing.T) { c.expectOK(c.GET("/email_poll")) c.expectEQ(len(c.emailSink), 1) - c.expectEQ(strings.Contains((<-c.emailSink).Body, "syzkaller has found reproducer"), true) + c.expectEQ(strings.Contains((<-c.emailSink).Body, "syzbot has found reproducer"), true) c.incomingEmail(sender, "#syz test: repo") c.expectEQ(len(c.emailSink), 1) @@ -129,8 +129,10 @@ test crash title test crash report -Tested on commit kernel_commit1 -repo1/branch1 +Tested on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 Patch is attached. Kernel config is attached. @@ -165,8 +167,10 @@ syzbot tried to test the proposed patch but build/boot failed: failed to apply patch -Tested on commit kernel_commit1 -repo1/branch1 +Tested on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 Patch is attached. Kernel config is attached. @@ -202,8 +206,10 @@ Reported-and-tested-by: syzbot+%v@testapp.appspotmail.com Note: the tag will also help syzbot to understand when the bug is fixed. -Tested on commit kernel_commit1 -repo1/branch1 +Tested on repo1/branch1 commit +kernel_commit1 (Sat Feb 3 04:05:06 0001 +0000) +kernel_commit_title1 + compiler: compiler1 Patch is attached. Kernel config is attached. diff --git a/dashboard/app/mail_bug.txt b/dashboard/app/mail_bug.txt index e14ce0288..8648cf442 100644 --- a/dashboard/app/mail_bug.txt +++ b/dashboard/app/mail_bug.txt @@ -2,15 +2,19 @@ Hello, {{end -}} -syzkaller {{if .First}}hit{{else}}has found reproducer for{{end}} the following crash on {{.KernelCommit}} -{{.KernelRepo}}/{{.KernelBranch}} -compiler: {{.CompilerID}} -.config is attached +syzbot {{if .First}}hit{{else}}has found reproducer for{{end}} the following crash on {{.KernelRepo}} commit +{{.KernelCommit}}{{if .KernelCommitDate}} ({{.KernelCommitDate}}){{end}}{{if .KernelCommitTitle}} +{{.KernelCommitTitle}}{{end}} + +compiler: {{.CompilerID}}{{if .UserSpaceArch}} +user-space arch: {{.UserSpaceArch}}{{end}} +.config is attached. {{if .HasLog}}Raw console output is attached. -{{end}}{{if .ReproC}}C reproducer is attached +{{end}}{{if .ReproC}}C reproducer is attached. {{end}}{{if .ReproSyz}}syzkaller reproducer is attached. See https://goo.gl/kgGztJ -for information about syzkaller reproducers -{{end}}{{if and (not .ReproC) (not .ReproSyz)}}Unfortunately, I don't have any reproducer for this bug yet. +for information about syzkaller reproducers. +{{end}}{{if and (not .ReproC) (not .ReproSyz)}}Unfortunately, I don't have any reproducer for this crash yet. +{{end}}{{if ne .NumCrashes 1}}So far this crash happened {{.NumCrashes}} times on {{formatList .HappenedOn}}. {{end}}{{if .Moderation}}CC: {{.Maintainers}}{{end}} IMPORTANT: if you fix the bug, please add the following tag to the commit: diff --git a/dashboard/app/mail_test_result.txt b/dashboard/app/mail_test_result.txt index 88f533d5b..6f61648d9 100644 --- a/dashboard/app/mail_test_result.txt +++ b/dashboard/app/mail_test_result.txt @@ -18,8 +18,10 @@ Reported-and-tested-by: {{.CreditEmail}} Note: the tag will also help syzbot to understand when the bug is fixed. {{end}} -Tested on commit {{.KernelCommit}} -{{.KernelRepo}}/{{.KernelBranch}} +Tested on {{.KernelRepo}} commit +{{.KernelCommit}}{{if .KernelCommitDate}} ({{.KernelCommitDate}}){{end}}{{if .KernelCommitTitle}} +{{.KernelCommitTitle}}{{end}} + compiler: {{.CompilerID}} Patch is attached. {{if .HasKernelConfig}}Kernel config is attached.{{end}} diff --git a/dashboard/app/reporting.go b/dashboard/app/reporting.go index a25c82610..adc009851 100644 --- a/dashboard/app/reporting.go +++ b/dashboard/app/reporting.go @@ -248,6 +248,8 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *datast ReproC: reproC, ReproSyz: reproSyz, CrashID: crashKey.IntID(), + NumCrashes: bug.NumCrashes, + HappenedOn: managersToRepos(c, bug.Namespace, bug.HappenedOn), } if bugReporting.CC != "" { rep.CC = strings.Split(bugReporting.CC, "|") @@ -255,6 +257,26 @@ func createBugReport(c context.Context, bug *Bug, crash *Crash, crashKey *datast return rep, nil } +func managersToRepos(c context.Context, ns string, managers []string) []string { + var repos []string + dedup := make(map[string]bool) + for _, manager := range managers { + build, err := lastManagerBuild(c, ns, manager) + if err != nil { + log.Errorf(c, "failed to get manager %q build: %v", manager, err) + continue + } + repo := kernelRepoInfo(build).Alias + if dedup[repo] { + continue + } + dedup[repo] = true + repos = append(repos, repo) + } + sort.Strings(repos) + return repos +} + // reportingPollClosed is called by backends to get list of closed bugs. func reportingPollClosed(c context.Context, ids []string) ([]string, error) { var bugs []*Bug diff --git a/dashboard/app/reporting_email.go b/dashboard/app/reporting_email.go index ae2feb6de..9e26fbbf4 100644 --- a/dashboard/app/reporting_email.go +++ b/dashboard/app/reporting_email.go @@ -12,6 +12,7 @@ import ( "net/mail" "strings" "text/template" + "time" "github.com/google/syzkaller/dashboard/dashapi" "github.com/google/syzkaller/pkg/email" @@ -192,42 +193,54 @@ func emailReport(c context.Context, rep *dashapi.BugReport, templ string) error if err != nil { return err } + userspaceArch := "" + if rep.Arch == "386" { + userspaceArch = "i386" + } // Data passed to the template. type BugReportData struct { - First bool - CreditEmail string - Moderation bool - Maintainers []string - CompilerID string - KernelRepo string - KernelBranch string - KernelCommit string - CrashTitle string - Report []byte - Error []byte - ErrorTruncated bool - HasLog bool - HasKernelConfig bool - ReproSyz bool - ReproC bool + First bool + CreditEmail string + Moderation bool + Maintainers []string + CompilerID string + KernelRepo string + KernelCommit string + KernelCommitTitle string + KernelCommitDate string + UserSpaceArch string + CrashTitle string + Report []byte + Error []byte + ErrorTruncated bool + HasLog bool + HasKernelConfig bool + ReproSyz bool + ReproC bool + NumCrashes int64 + HappenedOn []string } data := &BugReportData{ - First: rep.First, - CreditEmail: creditEmail, - Moderation: cfg.Moderation, - Maintainers: rep.Maintainers, - CompilerID: rep.CompilerID, - KernelRepo: rep.KernelRepo, - KernelBranch: rep.KernelBranch, - KernelCommit: rep.KernelCommit, - CrashTitle: rep.CrashTitle, - Report: rep.Report, - Error: errorText, - ErrorTruncated: errorTruncated, - HasLog: len(rep.Log) != 0, - HasKernelConfig: len(rep.KernelConfig) != 0, - ReproSyz: len(rep.ReproSyz) != 0, - ReproC: len(rep.ReproC) != 0, + First: rep.First, + CreditEmail: creditEmail, + Moderation: cfg.Moderation, + Maintainers: rep.Maintainers, + CompilerID: rep.CompilerID, + KernelRepo: rep.KernelRepoAlias, + KernelCommit: rep.KernelCommit, + KernelCommitTitle: rep.KernelCommitTitle, + KernelCommitDate: rep.KernelCommitDate.Format("Mon Jan 2 15:04:05 2006 -0700"), + UserSpaceArch: userspaceArch, + CrashTitle: rep.CrashTitle, + Report: rep.Report, + Error: errorText, + ErrorTruncated: errorTruncated, + HasLog: len(rep.Log) != 0, + HasKernelConfig: len(rep.KernelConfig) != 0, + ReproSyz: len(rep.ReproSyz) != 0, + ReproC: len(rep.ReproC) != 0, + NumCrashes: rep.NumCrashes, + HappenedOn: rep.HappenedOn, } log.Infof(c, "sending email %q to %q", rep.Title, to) err = sendMailTemplate(c, rep.Title, from, to, rep.ExtID, attachments, templ, data) @@ -407,8 +420,6 @@ func warnMailingListInCC(c context.Context, msg *email.Email, mailingList string } } -var mailTemplates = template.Must(template.New("").ParseGlob("mail_*.txt")) - func sendMailTemplate(c context.Context, subject, from string, to []string, replyTo string, attachments []aemail.Attachment, template string, data interface{}) error { body := new(bytes.Buffer) @@ -474,3 +485,24 @@ func ownEmails(c context.Context) []string { fmt.Sprintf("bot@%v.appspotmail.com", appengine.AppID(c)), } } + +func formatKernelTime(t time.Time) string { + if t.IsZero() { + return "" + } + // This is how dates appear in git log. + return t.Format("Mon Jan 2 15:04:05 2006 -0700") +} + +func formatStringList(list []string) string { + return strings.Join(list, ", ") +} + +var ( + mailTemplates = template.Must(template.New("").Funcs(mailFuncs).ParseGlob("mail_*.txt")) + + mailFuncs = template.FuncMap{ + "formatTime": formatKernelTime, + "formatList": formatStringList, + } +) diff --git a/dashboard/app/reporting_test.go b/dashboard/app/reporting_test.go index dbba2e626..e2b51d1c8 100644 --- a/dashboard/app/reporting_test.go +++ b/dashboard/app/reporting_test.go @@ -63,6 +63,8 @@ func TestReportBug(t *testing.T) { Log: []byte("log1"), Report: []byte("report1"), CrashID: rep.CrashID, + NumCrashes: 1, + HappenedOn: []string{"repo1/branch1"}, } c.expectEQ(rep, want) @@ -81,6 +83,7 @@ func TestReportBug(t *testing.T) { t.Fatal("get the same CrashID for new crash") } want.CrashID = reports[0].CrashID + want.NumCrashes = 2 c.expectEQ(reports[0], want) cmd := &dashapi.BugUpdate{ @@ -128,6 +131,7 @@ func TestReportBug(t *testing.T) { want.ID = rep2.ID want.First = true want.Config = []byte(`{"Index":2}`) + want.NumCrashes = 3 c.expectEQ(rep2, want) // Check that that we can't upstream the bug in the final reporting. @@ -234,6 +238,8 @@ func TestInvalidBug(t *testing.T) { Report: []byte("report2"), ReproC: []byte("int main() { return 1; }"), CrashID: rep.CrashID, + NumCrashes: 1, + HappenedOn: []string{"repo1/branch1"}, } c.expectEQ(rep, want) diff --git a/dashboard/dashapi/dashapi.go b/dashboard/dashapi/dashapi.go index c9b9ded15..6b1f6ab7b 100644 --- a/dashboard/dashapi/dashapi.go +++ b/dashboard/dashapi/dashapi.go @@ -231,6 +231,8 @@ type BugReport struct { ReproC []byte ReproSyz []byte CrashID int64 // returned back in BugUpdate + NumCrashes int64 + HappenedOn []string // list of kernel repo aliases CrashTitle string // job execution crash title Error []byte // job execution error -- cgit mrf-deployment