aboutsummaryrefslogtreecommitdiffstats
path: root/pkg/fuzzer
diff options
context:
space:
mode:
authorGrigory Bazilevich <g.bazilevich@ispras.ru>2026-03-11 09:42:40 +0300
committerGrigory Bazilevich <g.bazilevich@ispras.ru>2026-03-11 09:42:58 +0300
commita68fda52c366653ed73c240a6b9c3f4e750ccdfd (patch)
treea1702702b8f77c7838e42bb6dd690d803ccd2b30 /pkg/fuzzer
parent11e5f51b42b06a5e47fcb04b9796defcbb895ba3 (diff)
pkg/fuzzer,pkg/corpus: detection and preservation of programs with probability coverage
Diffstat (limited to 'pkg/fuzzer')
-rw-r--r--pkg/fuzzer/cover.go8
-rw-r--r--pkg/fuzzer/fuzzer.go12
-rw-r--r--pkg/fuzzer/job.go32
3 files changed, 40 insertions, 12 deletions
diff --git a/pkg/fuzzer/cover.go b/pkg/fuzzer/cover.go
index e2dca3d88..191ff1491 100644
--- a/pkg/fuzzer/cover.go
+++ b/pkg/fuzzer/cover.go
@@ -36,6 +36,14 @@ func (cover *Cover) addRawMaxSignal(signal []uint64, prio uint8) signal.Signal {
return diff
}
+func (cover *Cover) addMaxSignal(signal signal.Signal) signal.Signal {
+ cover.mu.Lock()
+ defer cover.mu.Unlock()
+ diff := cover.maxSignal.MergeDiff(signal)
+ cover.newSignal.Merge(diff)
+ return diff
+}
+
func (cover *Cover) CopyMaxSignal() signal.Signal {
cover.mu.RLock()
defer cover.mu.RUnlock()
diff --git a/pkg/fuzzer/fuzzer.go b/pkg/fuzzer/fuzzer.go
index bd55ca9c6..3241cb63a 100644
--- a/pkg/fuzzer/fuzzer.go
+++ b/pkg/fuzzer/fuzzer.go
@@ -24,8 +24,9 @@ import (
type Fuzzer struct {
Stats
- Config *Config
- Cover *Cover
+ Config *Config
+ Cover *Cover
+ ProbCover *Cover
ctx context.Context
mu sync.Mutex
@@ -50,9 +51,10 @@ func NewFuzzer(ctx context.Context, cfg *Config, rnd *rand.Rand,
}
}
f := &Fuzzer{
- Stats: newStats(target),
- Config: cfg,
- Cover: newCover(),
+ Stats: newStats(target),
+ Config: cfg,
+ Cover: newCover(),
+ ProbCover: new(Cover),
ctx: ctx,
rnd: rnd,
diff --git a/pkg/fuzzer/job.go b/pkg/fuzzer/job.go
index bbac544f6..1f450ff7e 100644
--- a/pkg/fuzzer/job.go
+++ b/pkg/fuzzer/job.go
@@ -93,7 +93,9 @@ type triageCall struct {
// Filled after deflake:
signals [deflakeNeedRuns]signal.Signal
+ probSignal signal.Signal
stableSignal signal.Signal
+ newProbSignal signal.Signal
newStableSignal signal.Signal
cover cover.Cover
rawCover []uint64
@@ -162,12 +164,16 @@ func (job *triageJob) run(fuzzer *Fuzzer) {
}
func (job *triageJob) handleCall(call int, info *triageCall) {
- if info.newStableSignal.Empty() {
+ skip := true
+ skip = skip && info.newStableSignal.Empty()
+ skip = skip && (info.newProbSignal.Empty() || info.newProbSignal.Len() < 4 && info.newProbSignal.Metric() < (1<<2))
+
+ if skip {
return
}
p := job.p
- if job.flags&ProgMinimized == 0 {
+ if job.flags&ProgMinimized == 0 && !info.newStableSignal.Empty() {
p, call = job.minimize(call, info)
if p == nil {
return
@@ -209,11 +215,13 @@ func (job *triageJob) handleCall(call int, info *triageCall) {
}
job.fuzzer.Logf(2, "added new input for %v to the corpus: %s", callName, p)
input := corpus.NewInput{
- Prog: p,
- Call: call,
- Signal: info.stableSignal,
- Cover: info.cover.Serialize(),
- RawCover: info.rawCover,
+ Prog: p,
+ Call: call,
+ ProbOnly: info.newStableSignal.Empty(),
+ Signal: info.probSignal,
+ StableSignal: info.stableSignal,
+ Cover: info.cover.Serialize(),
+ RawCover: info.rawCover,
}
job.fuzzer.Config.Corpus.Save(input)
}
@@ -291,6 +299,16 @@ func (job *triageJob) deflake(exec func(*queue.Request, ProgFlags) *queue.Result
}
job.info.Logf("deflake complete")
for call, info := range job.calls {
+ for i := range needRuns - 1 {
+ info.probSignal.Merge(info.signals[i].CopyWithPrio(uint8(i) << 2))
+ }
+ info.newProbSignal = job.fuzzer.ProbCover.addMaxSignal(info.probSignal)
+ job.info.Logf("call #%d [%s]: |probability signal|=%d, |new probability signal|=%d%s",
+ call, job.p.CallName(call), info.probSignal.Len(), info.newProbSignal.Len(),
+ signalPreview(info.newProbSignal))
+ }
+
+ for call, info := range job.calls {
info.stableSignal = info.signals[needRuns-1]
info.newStableSignal = info.newSignal.Intersection(info.stableSignal)
job.info.Logf("call #%d [%s]: |stable signal|=%d, |new stable signal|=%d%s",