From 71ed63015c8a77b1278197f6a0c472bbfef6d12f Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Mon, 27 Nov 2017 08:59:37 +0100 Subject: prog: mutate len arguments Fixes #183 --- prog/mutation.go | 25 +++++++++++++++---------- prog/rand.go | 2 +- prog/size.go | 55 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ prog/size_test.go | 3 --- 4 files changed, 71 insertions(+), 14 deletions(-) diff --git a/prog/mutation.go b/prog/mutation.go index 1aeef4fa4..0b2a5b026 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -62,14 +62,15 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro continue } s := analyze(ct, p, c) + updateSizes := true for stop := false; !stop; stop = r.oneOf(3) { - args, bases := p.Target.mutationArgs(c) + args, bases, parents := p.Target.mutationArgs(c) if len(args) == 0 { retry = true continue } idx := r.Intn(len(args)) - arg, base := args[idx], bases[idx] + arg, base, parent := args[idx], bases[idx], parents[idx] var baseSize uint64 if base != nil { b, ok := base.(*PointerArg) @@ -94,6 +95,12 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro a.Val ^= 1 << uint64(r.Intn(64)) } } + case *LenType: + if !r.mutateSize(arg.(*ConstArg), *parent) { + retry = true + continue + } + updateSizes = false case *ResourceType, *VmaType, *ProcType: arg1, calls1 := r.generateArg(s, arg.Type()) p.replaceArg(c, arg, arg1, calls1) @@ -200,8 +207,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro opt, calls := r.generateArg(s, optType) arg1 := MakeUnionArg(t, opt, optType) p.replaceArg(c, arg, arg1, calls) - case *LenType: - panic("bad arg returned by mutationArgs: LenType") case *CsumType: panic("bad arg returned by mutationArgs: CsumType") case *ConstType: @@ -227,7 +232,9 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro } // Update all len fields. - p.Target.assignSizesCall(c) + if updateSizes { + p.Target.assignSizesCall(c) + } } default: // Remove a random call. @@ -501,8 +508,8 @@ func (p *Prog) TrimAfter(idx int) { p.Calls = p.Calls[:idx+1] } -func (target *Target) mutationArgs(c *Call) (args, bases []Arg) { - foreachArg(c, func(arg, base Arg, _ *[]Arg) { +func (target *Target) mutationArgs(c *Call) (args, bases []Arg, parents []*[]Arg) { + foreachArg(c, func(arg, base Arg, parent *[]Arg) { switch typ := arg.Type().(type) { case *StructType: if target.SpecialStructs[typ.Name()] == nil { @@ -515,9 +522,6 @@ func (target *Target) mutationArgs(c *Call) (args, bases []Arg) { if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd { return } - case *LenType: - // Size is updated when the size-of arg change. - return case *CsumType: // Checksum is updated when the checksummed data changes. return @@ -541,6 +545,7 @@ func (target *Target) mutationArgs(c *Call) (args, bases []Arg) { } args = append(args, arg) bases = append(bases, base) + parents = append(parents, parent) }) return } diff --git a/prog/rand.go b/prog/rand.go index 173248599..2b5148181 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -96,7 +96,7 @@ func (r *randGen) randRangeInt(begin uint64, end uint64) uint64 { if r.oneOf(100) { return r.randInt() } - return begin + uint64(r.Int63n(int64(end-begin+1))) + return begin + (r.Uint64() % (end - begin + 1)) } // biasedRand returns a random int in range [0..n), diff --git a/prog/size.go b/prog/size.go index 718e0c426..5dd1310b4 100644 --- a/prog/size.go +++ b/prog/size.go @@ -106,3 +106,58 @@ func (target *Target) assignSizesArray(args []Arg) { func (target *Target) assignSizesCall(c *Call) { target.assignSizesArray(c.Args) } + +func (r *randGen) mutateSize(arg *ConstArg, parent []Arg) bool { + typ := arg.Type().(*LenType) + elemSize := typ.ByteSize + if elemSize == 0 { + elemSize = 1 + for _, field := range parent { + if typ.Buf != field.Type().FieldName() { + continue + } + if inner := InnerArg(field); inner != nil { + switch targetType := inner.Type().(type) { + case *VmaType: + return false + case *ArrayType: + elemSize = targetType.Type.Size() + } + } + break + } + } + if r.oneOf(100) { + arg.Val = r.rand64() + return true + } + if r.bin() { + // Small adjustment to trigger missed size checks. + if arg.Val != 0 && r.bin() { + arg.Val = r.randRangeInt(0, arg.Val-1) + } else { + arg.Val = r.randRangeInt(arg.Val+1, arg.Val+1000) + } + return true + } + // Try to provoke int overflows. + max := ^uint64(0) + if r.oneOf(3) { + max = 1<<32 - 1 + if r.oneOf(2) { + max = 1<<16 - 1 + if r.oneOf(2) { + max = 1<<8 - 1 + } + } + } + n := max / elemSize + delta := uint64(1000 - r.biasedRand(1000, 10)) + if elemSize == 1 || r.oneOf(10) { + n -= delta + } else { + n += delta + } + arg.Val = n + return true +} diff --git a/prog/size_test.go b/prog/size_test.go index 02c6470d4..d6a950fd6 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -25,9 +25,6 @@ func TestAssignSizeRandom(t *testing.T) { for _, call := range p.Calls { target.assignSizesCall(call) } - if data1 := p.Serialize(); !bytes.Equal(data0, data1) { - t.Fatalf("different lens assigned, initial:\n%s\nnew:\n%s", data0, data1) - } } } -- cgit mrf-deployment