Skip to content
Permalink
Browse files

prog: fix minimization bugs

Fix several nasty bugs in minimization that could lead
to almost arbitrary results. These bugs affected both
crash minimization and corpus population.
Extend the randomized test to catch these bugs.
Add additional asserts to code to catch similar bugs in future.

Reported-by @xairy
  • Loading branch information...
dvyukov committed Jul 2, 2019
1 parent 5f175e9 commit 55565fa0377f97cf09bfab365707e08b0156c11b
Showing with 40 additions and 13 deletions.
  1. +2 −2 prog/export_test.go
  2. +26 −7 prog/minimization.go
  3. +12 −4 prog/minimization_test.go
@@ -41,9 +41,9 @@ func randSource(t *testing.T) rand.Source {
}

func iterCount() int {
iters := 10000
iters := 1000
if testing.Short() {
iters = 100
iters /= 10
}
if raceEnabled {
iters /= 10
@@ -95,9 +95,21 @@ func (ctx *minimizeArgsCtx) do(arg Arg, path string) bool {
if ctx.triedPaths[path] {
return false
}
p0 := *ctx.p0
if arg.Type().minimize(ctx, arg, path) {
return true
}
if *ctx.p0 == ctx.p {
// If minimize committed a new program, it must return true.
// Otherwise *ctx.p0 and ctx.p will point to the same program
// and any temp mutations to ctx.p will unintentionally affect ctx.p0.
panic("shared program committed")
}
if *ctx.p0 != p0 {
// New program was committed, but we did not start iteration anew.
// This means we are iterating over a stale tree and any changes won't be visible.
panic("iterating over stale program")
}
ctx.triedPaths[path] = true
return false
}
@@ -191,9 +203,10 @@ func minimizeInt(ctx *minimizeArgsCtx, arg Arg, path string) bool {
a.Val = def.Val
if ctx.pred(ctx.p, ctx.callIndex0) {
*ctx.p0 = ctx.p
} else {
a.Val = v0
ctx.triedPaths[path] = true
return true
}
a.Val = v0
return false
}

@@ -210,11 +223,12 @@ func (typ *ResourceType) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bo
a.Res, a.Val = nil, typ.Default()
if ctx.pred(ctx.p, ctx.callIndex0) {
*ctx.p0 = ctx.p
} else {
a.Res, a.Val = r0, 0
a.Res.uses[a] = true
ctx.triedPaths[path] = true
return true
}
return false
a.Res, a.Val = r0, 0
a.Res.uses[a] = true
return true
}

func (typ *BufferType) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool {
@@ -223,6 +237,7 @@ func (typ *BufferType) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool
return false
}
a := arg.(*DataArg)
len0 := len(a.Data())
minLen := int(typ.RangeBegin)
for step := len(a.Data()) - minLen; len(a.Data()) > minLen && step > 0; {
if len(a.Data())-step >= minLen {
@@ -239,6 +254,10 @@ func (typ *BufferType) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool
break
}
}
*ctx.p0 = ctx.p
if len(a.Data()) != len0 {
*ctx.p0 = ctx.p
ctx.triedPaths[path] = true
return true
}
return false
}
@@ -142,15 +142,23 @@ func TestMinimize(t *testing.T) {
func TestMinimizeRandom(t *testing.T) {
target, rs, iters := initTest(t)
iters /= 10 // Long test.
r := rand.New(rs)
for i := 0; i < iters; i++ {
for _, crash := range []bool{false, true} {
p := target.Generate(rs, 5, nil)
Minimize(p, len(p.Calls)-1, crash, func(p1 *Prog, callIndex int) bool {
return false
})
Minimize(p, len(p.Calls)-1, crash, func(p1 *Prog, callIndex int) bool {
copyP := p.Clone()
minP, _ := Minimize(p, len(p.Calls)-1, crash, func(p1 *Prog, callIndex int) bool {
if r.Intn(2) == 0 {
return false
}
copyP = p1.Clone()
return true
})
got := string(minP.Serialize())
want := string(copyP.Serialize())
if got != want {
t.Fatalf("program:\n%s\ngot:\n%v\nwant:\n%s", string(p.Serialize()), got, want)
}
}
}
}

0 comments on commit 55565fa

Please sign in to comment.
You can’t perform that action at this time.