aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2017-11-27 08:59:37 +0100
committerDmitry Vyukov <dvyukov@google.com>2017-12-31 12:29:08 +0100
commit71ed63015c8a77b1278197f6a0c472bbfef6d12f (patch)
tree15c2b365f6f2ee30c2e694cec1953b08f5c0c01c /prog
parent6bfd4f1979d582602a91ee57865e588ffed41ab5 (diff)
prog: mutate len arguments
Fixes #183
Diffstat (limited to 'prog')
-rw-r--r--prog/mutation.go25
-rw-r--r--prog/rand.go2
-rw-r--r--prog/size.go55
-rw-r--r--prog/size_test.go3
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)
- }
}
}