aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-07-06 11:16:21 +0200
committerDmitry Vyukov <dvyukov@google.com>2017-07-06 12:17:39 +0200
commit76f45d87f2da4a2f6f7066797523d9457f71ad12 (patch)
tree87814eda96de07824dabea84c3bd64549850db05
parentf68d78b5a85be1b59350032055f60321fbbfc116 (diff)
syz-manager: save proper report for reproducers
We can start reproducing one crash, but end up reproducing another. Currently we still attribute the resulting repro to the original crash. This is wrong. Save the resulting desc/report for reproducers and use that in manager.
-rw-r--r--pkg/repro/repro.go8
-rw-r--r--syz-manager/manager.go71
2 files changed, 46 insertions, 33 deletions
diff --git a/pkg/repro/repro.go b/pkg/repro/repro.go
index b5e265301..bce549b0a 100644
--- a/pkg/repro/repro.go
+++ b/pkg/repro/repro.go
@@ -36,7 +36,10 @@ type Result struct {
Opts csource.Options
CRepro bool
Stats Stats
- Report []byte
+ // Description and report of the final crash that we reproduced.
+ // Can be different from what we started reproducing.
+ Desc string
+ Report []byte
}
type context struct {
@@ -45,6 +48,7 @@ type context struct {
instances chan *instance
bootRequests chan int
stats Stats
+ desc string
report []byte
}
@@ -137,6 +141,7 @@ func Run(crashLog []byte, cfg *mgrconfig.Config, vmPool *vm.Pool, vmIndexes []in
if res != nil {
ctx.reproLog(3, "repro crashed as:\n%s", string(ctx.report))
res.Stats = ctx.stats
+ res.Desc = ctx.desc
res.Report = ctx.report
}
@@ -666,6 +671,7 @@ func (ctx *context) testImpl(inst *vm.Instance, command string, duration time.Du
ctx.reproLog(2, "program did not crash")
return false, nil
}
+ ctx.desc = desc
ctx.report = report
ctx.reproLog(2, "program crashed: %v", desc)
return true, nil
diff --git a/syz-manager/manager.go b/syz-manager/manager.go
index 2eaa94778..9cb47d5f2 100644
--- a/syz-manager/manager.go
+++ b/syz-manager/manager.go
@@ -305,7 +305,7 @@ type RunResult struct {
type ReproResult struct {
instances []int
- crash *Crash
+ desc0 string
res *repro.Result
err error
}
@@ -373,7 +373,7 @@ func (mgr *Manager) vmLoop() {
Logf(1, "loop: starting repro of '%v' on instances %+v", crash.desc, vmIndexes)
go func() {
res, err := repro.Run(crash.output, mgr.cfg, mgr.vmPool, vmIndexes)
- reproDone <- &ReproResult{vmIndexes, crash, res, err}
+ reproDone <- &ReproResult{vmIndexes, crash.desc, res, err}
}()
}
for !canRepro() && len(instances) != 0 {
@@ -415,18 +415,24 @@ func (mgr *Manager) vmLoop() {
}
case res := <-reproDone:
crepro := false
+ desc := ""
if res.res != nil {
crepro = res.res.CRepro
+ desc = res.res.Desc
}
- Logf(1, "loop: repro on instances %+v finished '%v', repro=%v crepro=%v",
- res.instances, res.crash.desc, res.res != nil, crepro)
+ Logf(1, "loop: repro on %+v finished '%v', repro=%v crepro=%v desc='%v'",
+ res.instances, res.desc0, res.res != nil, crepro, desc)
if res.err != nil {
Logf(0, "repro failed: %v", res.err)
}
- delete(reproducing, res.crash.desc)
+ delete(reproducing, res.desc0)
instances = append(instances, res.instances...)
reproInstances -= instancesPerRepro
- mgr.saveRepro(res.crash, res.res)
+ if res.res == nil {
+ mgr.saveFailedRepro(res.desc0)
+ } else {
+ mgr.saveRepro(res.res)
+ }
case <-shutdown:
Logf(1, "loop: shutting down...")
shutdown = nil
@@ -599,37 +605,38 @@ func (mgr *Manager) needRepro(desc string) bool {
return false
}
-func (mgr *Manager) saveRepro(crash *Crash, res *repro.Result) {
- sig := hash.Hash([]byte(crash.desc))
- dir := filepath.Join(mgr.crashdir, sig.String())
- if res == nil {
- if mgr.dash != nil {
- fr := &dashapi.FailedRepro{
- Manager: mgr.cfg.Name,
- BuildID: mgr.cfg.Tag,
- Title: crash.desc,
- }
- if err := mgr.dash.ReportFailedRepro(fr); err != nil {
- Logf(0, "failed to report failed repro to dashboard: %v", err)
- }
+func (mgr *Manager) saveFailedRepro(desc string) {
+ if mgr.dash != nil {
+ fr := &dashapi.FailedRepro{
+ Manager: mgr.cfg.Name,
+ BuildID: mgr.cfg.Tag,
+ Title: desc,
}
- for i := 0; i < maxReproAttempts; i++ {
- name := filepath.Join(dir, fmt.Sprintf("repro%v", i))
- if !osutil.IsExist(name) {
- osutil.WriteFile(name, nil)
- break
- }
+ if err := mgr.dash.ReportFailedRepro(fr); err != nil {
+ Logf(0, "failed to report failed repro to dashboard: %v", err)
}
- return
}
+ dir := filepath.Join(mgr.crashdir, hash.String([]byte(desc)))
+ for i := 0; i < maxReproAttempts; i++ {
+ name := filepath.Join(dir, fmt.Sprintf("repro%v", i))
+ if !osutil.IsExist(name) {
+ osutil.WriteFile(name, nil)
+ break
+ }
+ }
+}
+
+func (mgr *Manager) saveRepro(res *repro.Result) {
+ dir := filepath.Join(mgr.crashdir, hash.String([]byte(res.Desc)))
+
opts := fmt.Sprintf("# %+v\n", res.Opts)
prog := res.Prog.Serialize()
osutil.WriteFile(filepath.Join(dir, "repro.prog"), append([]byte(opts), prog...))
if len(mgr.cfg.Tag) > 0 {
osutil.WriteFile(filepath.Join(dir, "repro.tag"), []byte(mgr.cfg.Tag))
}
- if len(crash.text) > 0 {
- osutil.WriteFile(filepath.Join(dir, "repro.report"), []byte(crash.text))
+ if len(res.Report) > 0 {
+ osutil.WriteFile(filepath.Join(dir, "repro.report"), []byte(res.Report))
}
osutil.WriteFile(filepath.Join(dir, "repro.log"), res.Stats.Log)
stats := fmt.Sprintf("Extracting prog: %s\nMinimizing prog: %s\nSimplifying prog options: %s\nExtracting C: %s\nSimplifying C: %s\n",
@@ -652,7 +659,7 @@ func (mgr *Manager) saveRepro(crash *Crash, res *repro.Result) {
if mgr.dash != nil {
var maintainers []string
- guiltyFile := report.ExtractGuiltyFile(crash.text)
+ guiltyFile := report.ExtractGuiltyFile(res.Report)
if guiltyFile != "" {
var err error
maintainers, err = report.GetMaintainers(mgr.cfg.Kernel_Src, guiltyFile)
@@ -663,10 +670,10 @@ func (mgr *Manager) saveRepro(crash *Crash, res *repro.Result) {
dc := &dashapi.Crash{
Manager: mgr.cfg.Name,
BuildID: mgr.cfg.Tag,
- Title: crash.desc,
+ Title: res.Desc,
Maintainers: maintainers,
- Log: crash.output,
- Report: crash.text,
+ Log: nil,
+ Report: res.Report,
ReproOpts: []byte(fmt.Sprintf("%+v", res.Opts)),
ReproSyz: []byte(res.Prog.Serialize()),
ReproC: cprogText,