diff options
| -rw-r--r-- | syz-manager/manager.go | 2 | ||||
| -rw-r--r-- | syz-manager/repro.go | 25 | ||||
| -rw-r--r-- | syz-manager/repro_test.go | 38 |
3 files changed, 62 insertions, 3 deletions
diff --git a/syz-manager/manager.go b/syz-manager/manager.go index 105117ef0..b7c69558a 100644 --- a/syz-manager/manager.go +++ b/syz-manager/manager.go @@ -155,6 +155,7 @@ type Crash struct { instanceName string fromHub bool // this crash was created based on a repro from syz-hub fromDashboard bool // .. or from dashboard + manual bool *report.Report } @@ -1614,6 +1615,7 @@ func (mgr *Manager) dashboardReproTasks() { if len(resp.CrashLog) > 0 { mgr.externalReproQueue <- &Crash{ fromDashboard: true, + manual: resp.Type == dashapi.ManualLog, Report: &report.Report{ Title: resp.Title, Output: resp.CrashLog, diff --git a/syz-manager/repro.go b/syz-manager/repro.go index 8a4e75c27..3e2b2a315 100644 --- a/syz-manager/repro.go +++ b/syz-manager/repro.go @@ -127,14 +127,33 @@ func (m *reproManager) popCrash() *Crash { m.mu.Lock() defer m.mu.Unlock() + newBetter := func(base, new *Crash) bool { + // First, serve manual requests. + if new.manual != base.manual { + return new.manual + } + // Then, deprioritize hub reproducers. + if new.fromHub != base.fromHub { + return !new.fromHub + } + return false + } + + idx := -1 for i, crash := range m.queue { if m.reproducing[crash.FullTitle()] { continue } - m.queue = slices.Delete(m.queue, i, i+1) - return crash + if idx == -1 || newBetter(m.queue[idx], m.queue[i]) { + idx = i + } + } + if idx == -1 { + return nil } - return nil + crash := m.queue[idx] + m.queue = slices.Delete(m.queue, idx, idx+1) + return crash } func (m *reproManager) Loop(ctx context.Context) { diff --git a/syz-manager/repro_test.go b/syz-manager/repro_test.go index 79b482d36..8042c7042 100644 --- a/syz-manager/repro_test.go +++ b/syz-manager/repro_test.go @@ -67,6 +67,44 @@ func TestReproManager(t *testing.T) { t.Fatal("reserved VMs must have dropped to 0") } +func TestReproOrder(t *testing.T) { + mock := &reproMgrMock{ + run: make(chan runCallback), + } + obj := newReproManager(mock, 3, false) + + // The right order is A B C. + crashes := []*Crash{ + { + Report: &report.Report{Title: "A"}, + fromDashboard: true, + manual: true, + }, + { + Report: &report.Report{Title: "B"}, + fromDashboard: true, + }, + { + Report: &report.Report{Title: "C"}, + fromHub: true, + }, + } + + obj.Enqueue(crashes[2]) + obj.Enqueue(crashes[1]) + obj.Enqueue(crashes[0]) + assert.Equal(t, crashes[0], obj.popCrash()) + assert.Equal(t, crashes[1], obj.popCrash()) + assert.Equal(t, crashes[2], obj.popCrash()) + + obj.Enqueue(crashes[1]) + obj.Enqueue(crashes[0]) + obj.Enqueue(crashes[2]) + assert.Equal(t, crashes[0], obj.popCrash()) + assert.Equal(t, crashes[1], obj.popCrash()) + assert.Equal(t, crashes[2], obj.popCrash()) +} + type reproMgrMock struct { reserved atomic.Int64 run chan runCallback |
