diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-06-11 10:02:49 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-06-11 12:12:01 +0300 |
| commit | b30b1136b621a3b829bb4b80487e776fbfa0a2b0 (patch) | |
| tree | ab25cbc40e70bbc47f47ebc1c63709a535b30d74 | |
| parent | a7429096651d84e6a9cf6232f0166c23fbdee2ee (diff) | |
dashboard/app: try 1 repro per day until we have at least syz repro
Bugs without repros are not actionable sometimes.
Fixes #627
| -rw-r--r-- | dashboard/app/api.go | 19 | ||||
| -rw-r--r-- | dashboard/app/entities.go | 1 | ||||
| -rw-r--r-- | dashboard/app/repro_test.go | 37 |
3 files changed, 43 insertions, 14 deletions
diff --git a/dashboard/app/api.go b/dashboard/app/api.go index 93ae5a275..8bf27cdc7 100644 --- a/dashboard/app/api.go +++ b/dashboard/app/api.go @@ -52,7 +52,10 @@ type JSONHandler func(c context.Context, r *http.Request) (interface{}, error) type APIHandler func(c context.Context, r *http.Request, payload []byte) (interface{}, error) type APINamespaceHandler func(c context.Context, ns string, r *http.Request, payload []byte) (interface{}, error) -const maxReproPerBug = 10 +const ( + maxReproPerBug = 10 + reproRetryPeriod = 24 * time.Hour // try 1 repro per day until we have at least syz repro +) // Overridable for testing. var timeNow = func(c context.Context) time.Time { @@ -572,6 +575,7 @@ func reportCrash(c context.Context, ns string, req *dashapi.Crash) (*Bug, error) } if reproLevel != ReproLevelNone { bug.NumRepro++ + bug.LastReproTime = now } if bug.ReproLevel < reproLevel { bug.ReproLevel = reproLevel @@ -674,12 +678,14 @@ func apiReportFailedRepro(c context.Context, ns string, r *http.Request, payload if bug == nil { return nil, fmt.Errorf("%v: can't find bug for crash %q", ns, req.Title) } + now := timeNow(c) tx := func(c context.Context) error { bug := new(Bug) if err := datastore.Get(c, bugKey, bug); err != nil { return fmt.Errorf("failed to get bug: %v", err) } bug.NumRepro++ + bug.LastReproTime = now if _, err := datastore.Put(c, bugKey, bug); err != nil { return fmt.Errorf("failed to put bug: %v", err) } @@ -825,7 +831,7 @@ func isActiveBug(c context.Context, bug *Bug) (bool, error) { } func needRepro(c context.Context, bug *Bug) bool { - if !needReproForBug(bug) { + if !needReproForBug(c, bug) { return false } canon, err := canonicalBug(c, bug) @@ -833,14 +839,15 @@ func needRepro(c context.Context, bug *Bug) bool { log.Errorf(c, "failed to get canonical bug: %v", err) return false } - return needReproForBug(canon) + return needReproForBug(c, canon) } -func needReproForBug(bug *Bug) bool { +func needReproForBug(c context.Context, bug *Bug) bool { return bug.ReproLevel < ReproLevelC && - bug.NumRepro < maxReproPerBug && len(bug.Commits) == 0 && - bug.Title != corruptedReportTitle + bug.Title != corruptedReportTitle && + (bug.NumRepro < maxReproPerBug || + bug.ReproLevel == ReproLevelNone && timeSince(c, bug.LastReproTime) > reproRetryPeriod) } func putText(c context.Context, ns, tag string, data []byte, dedup bool) (int64, error) { diff --git a/dashboard/app/entities.go b/dashboard/app/entities.go index 0f4b604e7..fd0325cf3 100644 --- a/dashboard/app/entities.go +++ b/dashboard/app/entities.go @@ -77,6 +77,7 @@ type Bug struct { FirstTime time.Time LastTime time.Time LastSavedCrash time.Time + LastReproTime time.Time Closed time.Time Reporting []BugReporting Commits []string diff --git a/dashboard/app/repro_test.go b/dashboard/app/repro_test.go index 3bb37a6d3..25f0ad938 100644 --- a/dashboard/app/repro_test.go +++ b/dashboard/app/repro_test.go @@ -7,6 +7,7 @@ package dash import ( "testing" + "time" "github.com/google/syzkaller/dashboard/dashapi" ) @@ -87,17 +88,29 @@ func testNeedRepro3(t *testing.T, crashCtor func(c *Ctx) *dashapi.Crash) { for i := 0; i < maxReproPerBug; i++ { resp, _ := c.client.ReportCrash(crash1) c.expectEQ(resp.NeedRepro, true) - needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) c.expectEQ(needRepro, true) c.client.ReportFailedRepro(testCrashID(crash1)) } - resp, _ := c.client.ReportCrash(crash1) - c.expectEQ(resp.NeedRepro, false) - - needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) - c.expectEQ(needRepro, false) + for i := 0; i < 3; i++ { + // No more repros today. + c.advanceTime(time.Hour) + resp, _ := c.client.ReportCrash(crash1) + c.expectEQ(resp.NeedRepro, false) + needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) + c.expectEQ(needRepro, false) + + // Then another repro after a day. + c.advanceTime(25 * time.Hour) + for j := 0; j < 2; j++ { + resp, _ := c.client.ReportCrash(crash1) + c.expectEQ(resp.NeedRepro, true) + needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) + c.expectEQ(needRepro, true) + } + c.client.ReportFailedRepro(testCrashID(crash1)) + } } func TestNeedRepro3_normal(t *testing.T) { testNeedRepro3(t, normalCrash) } @@ -116,16 +129,24 @@ func testNeedRepro4(t *testing.T, crashCtor func(c *Ctx) *dashapi.Crash) { for i := 0; i < maxReproPerBug-1; i++ { resp, _ := c.client.ReportCrash(crash1) c.expectEQ(resp.NeedRepro, true) - needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) c.expectEQ(needRepro, true) } resp, _ := c.client.ReportCrash(crash1) c.expectEQ(resp.NeedRepro, false) - needRepro, _ := c.client.NeedRepro(testCrashID(crash1)) c.expectEQ(needRepro, false) + + // No more repros even after a day. + c.advanceTime(25 * time.Hour) + crash1.ReproOpts = nil + crash1.ReproSyz = nil + + resp, _ = c.client.ReportCrash(crash1) + c.expectEQ(resp.NeedRepro, false) + needRepro, _ = c.client.NeedRepro(testCrashID(crash1)) + c.expectEQ(needRepro, false) } func TestNeedRepro4_normal(t *testing.T) { testNeedRepro4(t, normalCrash) } |
