Skip to content

Commit

Permalink
dashboard/app: try 1 repro per day until we have at least syz repro
Browse files Browse the repository at this point in the history
Bugs without repros are not actionable sometimes.

Fixes #627
  • Loading branch information
dvyukov committed Jun 11, 2018
1 parent a742909 commit b30b113
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 14 deletions.
19 changes: 13 additions & 6 deletions dashboard/app/api.go
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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)
}
Expand Down Expand Up @@ -825,22 +831,23 @@ 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)
if err != nil {
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) {
Expand Down
1 change: 1 addition & 0 deletions dashboard/app/entities.go
Expand Up @@ -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
Expand Down
37 changes: 29 additions & 8 deletions dashboard/app/repro_test.go
Expand Up @@ -7,6 +7,7 @@ package dash

import (
"testing"
"time"

"github.com/google/syzkaller/dashboard/dashapi"
)
Expand Down Expand Up @@ -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) }
Expand All @@ -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) }
Expand Down

0 comments on commit b30b113

Please sign in to comment.