aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/fuzzer/job.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2024-05-28 19:02:33 +0200
committerDmitry Vyukov <dvyukov@google.com>2024-06-03 15:04:36 +0000
commit1391da26937e63c018202fb53ab080d816a758ce (patch)
tree69925481294884f86a2eea9df66b65a4ac392541 /pkg/fuzzer/job.go
parent4dfd0208613afc9866f22849f14d5c9923d97194 (diff)
pkg/fuzzer: improve triage procedure
1. Use the initial signal as the first attempt, this should reduce total number of runs by 1 in common case. 2. Update max signal on each attempt. If should eliminate additional runs later. 3. Update the signal we are chasing after each attempt. It's possible that we won't get any of the orignal new signal, but instead will get some other stable new signal.
Diffstat (limited to 'pkg/fuzzer/job.go')
-rw-r--r--pkg/fuzzer/job.go29
1 files changed, 18 insertions, 11 deletions
diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go
index 9d51ec2d8..66013b0e2 100644
--- a/pkg/fuzzer/job.go
+++ b/pkg/fuzzer/job.go
@@ -77,7 +77,7 @@ func (job *triageJob) run(fuzzer *Fuzzer) {
fuzzer.Logf(3, "triaging input for %v (new signal=%v)", callName, job.newSignal.Len())
// Compute input coverage and non-flaky signal for minimization.
- info, stop := job.deflake(job.execute, fuzzer.statExecTriage, fuzzer.Config.FetchRawCover)
+ info, stop := job.deflake(job.execute, fuzzer.Cover, fuzzer.statExecTriage, fuzzer.Config.FetchRawCover)
if stop || info.newStableSignal.Empty() {
return
}
@@ -114,8 +114,8 @@ type deflakedCover struct {
rawCover []uint64
}
-func (job *triageJob) deflake(exec func(*queue.Request, ProgFlags) *queue.Result, stat *stats.Val,
- rawCover bool) (info deflakedCover, stop bool) {
+func (job *triageJob) deflake(exec func(*queue.Request, ProgFlags) *queue.Result, cover *Cover,
+ 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
// to 3 out of 5 runs.
@@ -126,7 +126,8 @@ func (job *triageJob) deflake(exec func(*queue.Request, ProgFlags) *queue.Result
maxRuns = 5
)
signals := make([]signal.Signal, needRuns)
- for i := 0; i < maxRuns; i++ {
+ signals[0] = job.newSignal.Copy()
+ for i := 1; i < maxRuns; i++ {
if job.newSignal.IntersectsWith(signals[needRuns-1]) {
// We already have the right deflaked signal.
break
@@ -150,11 +151,16 @@ func (job *triageJob) deflake(exec func(*queue.Request, ProgFlags) *queue.Result
// The call was not executed or failed.
continue
}
- thisSignal, thisCover := getSignalAndCover(job.p, result.Info, job.call)
+ inf, thisSignal, prio := getSignalAndCover(job.p, result.Info, job.call)
if len(info.rawCover) == 0 && rawCover {
- info.rawCover = thisCover
+ info.rawCover = inf.Cover
}
- info.cover.Merge(thisCover)
+ newMaxSignal := cover.addRawMaxSignal(inf.Signal, prio)
+ // Since signal may be flaky, update the new signal we are chasing.
+ // It's possible that we won't get any of the orignal new signal,
+ // but instead will get some other stable new signal.
+ job.newSignal.Merge(newMaxSignal)
+ info.cover.Merge(inf.Cover)
for j := len(signals) - 1; j > 0; j-- {
intersect := signals[j-1].Intersection(thisSignal)
signals[j].Merge(intersect)
@@ -191,7 +197,7 @@ func (job *triageJob) minimize(newSignal signal.Signal) (stop bool) {
// The call was not executed or failed.
continue
}
- thisSignal, _ := getSignalAndCover(p1, info, call1)
+ _, thisSignal, _ := getSignalAndCover(p1, info, call1)
if newSignal.Intersection(thisSignal).Len() == newSignal.Len() {
return true
}
@@ -216,15 +222,16 @@ func reexecutionSuccess(info *flatrpc.ProgInfo, oldInfo *flatrpc.CallInfo, call
return info.Extra != nil && len(info.Extra.Signal) != 0
}
-func getSignalAndCover(p *prog.Prog, info *flatrpc.ProgInfo, call int) (signal.Signal, []uint64) {
+func getSignalAndCover(p *prog.Prog, info *flatrpc.ProgInfo, call int) (*flatrpc.CallInfo, signal.Signal, uint8) {
inf := info.Extra
if call != -1 {
inf = info.Calls[call]
}
if inf == nil {
- return nil, nil
+ return nil, nil, 0
}
- return signal.FromRaw(inf.Signal, signalPrio(p, inf, call)), inf.Cover
+ prio := signalPrio(p, inf, call)
+ return inf, signal.FromRaw(inf.Signal, prio), prio
}
type smashJob struct {