From 2f25d0f441166a6b106eba49d9a256eb825b644b Mon Sep 17 00:00:00 2001 From: Aleksandr Nogikh Date: Thu, 16 May 2024 13:41:53 +0200 Subject: pkg/fuzzer: simplify prog execution options For now, only ProgTypes is enough. --- pkg/fuzzer/fuzzer.go | 37 ++++++++++++++----------------------- pkg/fuzzer/job.go | 11 ++++++----- pkg/fuzzer/job_test.go | 4 ++-- 3 files changed, 22 insertions(+), 30 deletions(-) (limited to 'pkg') diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go index 10056b528..bdcfeb2fb 100644 --- a/pkg/fuzzer/fuzzer.go +++ b/pkg/fuzzer/fuzzer.go @@ -92,45 +92,36 @@ func newExecQueues(fuzzer *Fuzzer) execQueues { return ret } -type execOpt any -type dontTriage struct{} -type progFlags ProgTypes +func (fuzzer *Fuzzer) execute(executor queue.Executor, req *queue.Request) *queue.Result { + return fuzzer.executeWithFlags(executor, req, 0) +} -func (fuzzer *Fuzzer) execute(executor queue.Executor, req *queue.Request, opts ...execOpt) *queue.Result { +func (fuzzer *Fuzzer) executeWithFlags(executor queue.Executor, req *queue.Request, flags ProgTypes) *queue.Result { executor.Submit(req) res := req.Wait(fuzzer.ctx) - fuzzer.processResult(req, res, opts...) + fuzzer.processResult(req, res, flags) return res } -func (fuzzer *Fuzzer) prepare(req *queue.Request, opts ...execOpt) { +func (fuzzer *Fuzzer) prepare(req *queue.Request, flags ProgTypes) { req.OnDone(func(req *queue.Request, res *queue.Result) bool { - fuzzer.processResult(req, res, opts...) + fuzzer.processResult(req, res, flags) return true }) } -func (fuzzer *Fuzzer) enqueue(executor queue.Executor, req *queue.Request, opts ...execOpt) { - fuzzer.prepare(req, opts...) +func (fuzzer *Fuzzer) enqueue(executor queue.Executor, req *queue.Request, flags ProgTypes) { + fuzzer.prepare(req, flags) executor.Submit(req) } -func (fuzzer *Fuzzer) processResult(req *queue.Request, res *queue.Result, opts ...execOpt) { - var flags ProgTypes - var noTriage bool - for _, opt := range opts { - switch v := opt.(type) { - case progFlags: - flags = ProgTypes(v) - case dontTriage: - noTriage = true - } - } +func (fuzzer *Fuzzer) processResult(req *queue.Request, res *queue.Result, flags ProgTypes) { + inTriage := flags&progInTriage > 0 // Triage individual calls. // We do it before unblocking the waiting threads because // it may result it concurrent modification of req.Prog. // If we are already triaging this exact prog, this is flaky coverage. - if req.ExecOpts.ExecFlags&ipc.FlagCollectSignal > 0 && res.Info != nil && !noTriage { + if req.ExecOpts.ExecFlags&ipc.FlagCollectSignal > 0 && res.Info != nil && !inTriage { for call, info := range res.Info.Calls { fuzzer.triageProgCall(req.Prog, &info, call, flags) } @@ -210,7 +201,7 @@ func (fuzzer *Fuzzer) genFuzz() *queue.Request { if req == nil { req = genProgRequest(fuzzer, rnd) } - fuzzer.prepare(req) + fuzzer.prepare(req, 0) return req } @@ -251,7 +242,7 @@ type Candidate struct { func (fuzzer *Fuzzer) AddCandidates(candidates []Candidate) { for _, candidate := range candidates { req, flags := candidateRequest(fuzzer, candidate) - fuzzer.enqueue(fuzzer.candidateQueue, req, progFlags(flags)) + fuzzer.enqueue(fuzzer.candidateQueue, req, flags) } } diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go index 2ec415bdb..174acdc52 100644 --- a/pkg/fuzzer/job.go +++ b/pkg/fuzzer/job.go @@ -26,6 +26,7 @@ const ( progCandidate ProgTypes = 1 << iota progMinimized progSmashed + progInTriage ) func genProgRequest(fuzzer *Fuzzer, rnd *rand.Rand) *queue.Request { @@ -88,9 +89,9 @@ type triageJob struct { queue queue.Executor } -func (job *triageJob) execute(req *queue.Request, opts ...execOpt) *queue.Result { +func (job *triageJob) execute(req *queue.Request, flags ProgTypes) *queue.Result { req.Important = true // All triage executions are important. - return job.fuzzer.execute(job.queue, req, opts...) + return job.fuzzer.executeWithFlags(job.queue, req, flags) } func (job *triageJob) run(fuzzer *Fuzzer) { @@ -138,7 +139,7 @@ type deflakedCover struct { rawCover []uint32 } -func (job *triageJob) deflake(exec func(*queue.Request, ...execOpt) *queue.Result, stat *stats.Val, +func (job *triageJob) deflake(exec func(*queue.Request, ProgTypes) *queue.Result, stat *stats.Val, rawCover bool) (info deflakedCover, stop bool) { // As demonstrated in #4639, programs reproduce with a very high, but not 100% probability. // The triage algorithm must tolerate this, so let's pick the signal that is common @@ -165,7 +166,7 @@ func (job *triageJob) deflake(exec func(*queue.Request, ...execOpt) *queue.Resul ExecOpts: setFlags(ipc.FlagCollectCover | ipc.FlagCollectSignal), ReturnAllSignal: true, Stat: stat, - }, &dontTriage{}) + }, progInTriage) if result.Stop() { stop = true return @@ -205,7 +206,7 @@ func (job *triageJob) minimize(newSignal signal.Signal) (stop bool) { SignalFilter: newSignal, SignalFilterCall: call1, Stat: job.fuzzer.statExecMinimize, - }) + }, 0) if result.Stop() { stop = true return false diff --git a/pkg/fuzzer/job_test.go b/pkg/fuzzer/job_test.go index 59f0e7097..b7718134b 100644 --- a/pkg/fuzzer/job_test.go +++ b/pkg/fuzzer/job_test.go @@ -29,7 +29,7 @@ func TestDeflakeFail(t *testing.T) { } run := 0 - ret, stop := testJob.deflake(func(_ *queue.Request, _ ...execOpt) *queue.Result { + ret, stop := testJob.deflake(func(_ *queue.Request, _ ProgTypes) *queue.Result { run++ // For first, we return 0 and 1. For second, 1 and 2. And so on. return fakeResult(0, []uint32{uint32(run), uint32(run + 1)}, []uint32{10, 20}) @@ -54,7 +54,7 @@ func TestDeflakeSuccess(t *testing.T) { newSignal: signal.FromRaw([]uint32{0, 1, 2}, 0), } run := 0 - ret, stop := testJob.deflake(func(_ *queue.Request, _ ...execOpt) *queue.Result { + ret, stop := testJob.deflake(func(_ *queue.Request, _ ProgTypes) *queue.Result { run++ switch run { case 1: -- cgit mrf-deployment