diff options
Diffstat (limited to 'pkg')
| -rw-r--r-- | pkg/repro/repro.go | 86 |
1 files changed, 48 insertions, 38 deletions
diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go index db943a9b8..d2076ffbf 100644 --- a/pkg/repro/repro.go +++ b/pkg/repro/repro.go @@ -45,19 +45,20 @@ type Stats struct { } type reproContext struct { - exec execInterface - logf func(string, ...interface{}) - target *targets.Target - crashTitle string - crashType crash.Type - crashStart int - crashExecutor *report.ExecutorInfo - entries []*prog.LogEntry - testTimeouts []time.Duration - startOpts csource.Options - stats *Stats - report *report.Report - timeouts targets.Timeouts + exec execInterface + logf func(string, ...interface{}) + target *targets.Target + crashTitle string + crashType crash.Type + crashStart int + crashExecutor *report.ExecutorInfo + entries []*prog.LogEntry + testTimeouts []time.Duration + startOpts csource.Options + stats *Stats + report *report.Report + timeouts targets.Timeouts + observedTitles map[string]bool } // execInterface describes the interfaces needed by pkg/repro. @@ -126,11 +127,12 @@ func prepareCtx(crashLog []byte, cfg *mgrconfig.Config, features flatrpc.Feature crashStart: crashStart, crashExecutor: crashExecutor, - entries: entries, - testTimeouts: testTimeouts, - startOpts: createStartOptions(cfg, features, crashType), - stats: new(Stats), - timeouts: cfg.Timeouts, + entries: entries, + testTimeouts: testTimeouts, + startOpts: createStartOptions(cfg, features, crashType), + stats: new(Stats), + timeouts: cfg.Timeouts, + observedTitles: map[string]bool{}, } ctx.reproLogf(0, "%v programs, timeouts %v", len(entries), testTimeouts) return ctx, nil @@ -148,9 +150,9 @@ func (ctx *reproContext) run() (*Result, *Stats, error) { for attempts := 0; ctx.report.Corrupted && attempts < 3; attempts++ { ctx.reproLogf(3, "report is corrupted, running repro again") if res.CRepro { - _, err = ctx.testCProg(res.Prog, res.Duration, res.Opts) + _, err = ctx.testCProg(res.Prog, res.Duration, res.Opts, false) } else { - _, err = ctx.testProg(res.Prog, res.Duration, res.Opts) + _, err = ctx.testProg(res.Prog, res.Duration, res.Opts, false) } if err != nil { return nil, nil, err @@ -328,7 +330,7 @@ func (ctx *reproContext) extractProgSingle(entries []*prog.LogEntry, duration ti opts := ctx.startOpts for _, ent := range entries { - ret, err := ctx.testProg(ent.P, duration, opts) + ret, err := ctx.testProg(ent.P, duration, opts, false) if err != nil { return nil, err } @@ -356,7 +358,7 @@ func (ctx *reproContext) extractProgBisect(entries []*prog.LogEntry, baseDuratio } // First check if replaying the log may crash the kernel at all. - ret, err := ctx.testProgs(entries, duration(len(entries)), opts) + ret, err := ctx.testProgs(entries, duration(len(entries)), opts, false) if !ret.Crashed { ctx.reproLogf(3, "replaying the whole log did not cause a kernel crash") return nil, nil @@ -367,7 +369,7 @@ func (ctx *reproContext) extractProgBisect(entries []*prog.LogEntry, baseDuratio // Bisect the log to find multiple guilty programs. entries, err = ctx.bisectProgs(entries, func(progs []*prog.LogEntry) (bool, error) { - ret, err := ctx.testProgs(progs, duration(len(progs)), opts) + ret, err := ctx.testProgs(progs, duration(len(progs)), opts, false) return ret.Crashed, err }) if err != nil { @@ -410,7 +412,7 @@ func (ctx *reproContext) concatenateProgs(entries []*prog.LogEntry, dur time.Dur if i+1 < len(entries) { newEntries = append(newEntries, entries[i+1:]...) } - ret, err := ctx.testProgs(newEntries, dur, ctx.startOpts) + ret, err := ctx.testProgs(newEntries, dur, ctx.startOpts, false) if err != nil { ctx.reproLogf(0, "concatenation step failed with %v", err) return false @@ -430,7 +432,7 @@ func (ctx *reproContext) concatenateProgs(entries []*prog.LogEntry, dur time.Dur ctx.reproLogf(2, "bisect: concatenated prog still exceeds %d calls", prog.MaxCalls) return nil, nil } - ret, err := ctx.testProg(p, dur, ctx.startOpts) + ret, err := ctx.testProg(p, dur, ctx.startOpts, false) if err != nil { ctx.reproLogf(3, "bisect: error during concatenation testing: %v", err) return nil, err @@ -462,7 +464,7 @@ func (ctx *reproContext) minimizeProg(res *Result) (*Result, error) { // will immediately exit. return false } - ret, err := ctx.testProg(p1, res.Duration, res.Opts) + ret, err := ctx.testProg(p1, res.Duration, res.Opts, false) if err != nil { ctx.reproLogf(0, "minimization failed with %v", err) return false @@ -487,7 +489,7 @@ func (ctx *reproContext) simplifyProg(res *Result) (*Result, error) { if !simplify(&opts) || !checkOpts(&opts, ctx.timeouts, res.Duration) { continue } - ret, err := ctx.testProg(res.Prog, res.Duration, opts) + ret, err := ctx.testProg(res.Prog, res.Duration, opts, true) if err != nil { return nil, err } @@ -516,7 +518,7 @@ func (ctx *reproContext) extractC(res *Result) (*Result, error) { ctx.stats.ExtractCTime = time.Since(start) }() - ret, err := ctx.testCProg(res.Prog, res.Duration, res.Opts) + ret, err := ctx.testCProg(res.Prog, res.Duration, res.Opts, true) if err != nil { return nil, err } @@ -537,7 +539,7 @@ func (ctx *reproContext) simplifyC(res *Result) (*Result, error) { if !simplify(&opts) || !checkOpts(&opts, ctx.timeouts, res.Duration) { continue } - ret, err := ctx.testCProg(res.Prog, res.Duration, opts) + ret, err := ctx.testCProg(res.Prog, res.Duration, opts, true) if err != nil { return nil, err } @@ -572,10 +574,10 @@ func checkOpts(opts *csource.Options, timeouts targets.Timeouts, timeout time.Du return true } -func (ctx *reproContext) testProg(p *prog.Prog, duration time.Duration, - opts csource.Options) (ret verdict, err error) { +func (ctx *reproContext) testProg(p *prog.Prog, duration time.Duration, opts csource.Options, + strict bool) (ret verdict, err error) { entry := prog.LogEntry{P: p} - return ctx.testProgs([]*prog.LogEntry{&entry}, duration, opts) + return ctx.testProgs([]*prog.LogEntry{&entry}, duration, opts, strict) } type verdict struct { @@ -583,7 +585,7 @@ type verdict struct { Duration time.Duration } -func (ctx *reproContext) getVerdict(callback func() (rep *instance.RunResult, err error)) ( +func (ctx *reproContext) getVerdict(callback func() (rep *instance.RunResult, err error), strict bool) ( verdict, error) { var result *instance.RunResult var err error @@ -614,6 +616,14 @@ func (ctx *reproContext) getVerdict(callback func() (rep *instance.RunResult, er ctx.reproLogf(2, "not a leak crash: %v", rep.Title) return verdict{false, result.Duration}, nil } + if strict && len(ctx.observedTitles) > 0 { + if !ctx.observedTitles[rep.Title] { + ctx.reproLogf(2, "a never seen crash title: %v, ignore", rep.Title) + return verdict{false, result.Duration}, nil + } + } else { + ctx.observedTitles[rep.Title] = true + } ctx.report = rep return verdict{true, result.Duration}, nil } @@ -631,8 +641,8 @@ func encodeEntries(entries []*prog.LogEntry) []byte { return buf.Bytes() } -func (ctx *reproContext) testProgs(entries []*prog.LogEntry, duration time.Duration, opts csource.Options) ( - ret verdict, err error) { +func (ctx *reproContext) testProgs(entries []*prog.LogEntry, duration time.Duration, opts csource.Options, + strict bool) (ret verdict, err error) { if len(entries) == 0 { return ret, fmt.Errorf("no programs to execute") } @@ -652,14 +662,14 @@ func (ctx *reproContext) testProgs(entries []*prog.LogEntry, duration time.Durat ctx.reproLogf(3, "detailed listing:\n%s", pstr) return ctx.getVerdict(func() (*instance.RunResult, error) { return ctx.exec.RunSyzProg(pstr, duration, opts, instance.SyzExitConditions) - }) + }, strict) } func (ctx *reproContext) testCProg(p *prog.Prog, duration time.Duration, - opts csource.Options) (ret verdict, err error) { + opts csource.Options, strict bool) (ret verdict, err error) { return ctx.getVerdict(func() (*instance.RunResult, error) { return ctx.exec.RunCProg(p, duration, opts) - }) + }, strict) } func (ctx *reproContext) reproLogf(level int, format string, args ...interface{}) { |
