aboutsummaryrefslogtreecommitdiffstats
path: root/prog/mutation.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-01-26 12:34:02 +0100
committerDmitry Vyukov <dvyukov@google.com>2018-01-27 17:08:43 +0100
commite8b49705479678b38c0068e84f1f599af8829184 (patch)
tree4010754d8153c508159c24fe6ac2caeddaf4f284 /prog/mutation.go
parent1d18b11287c0248782efe867659c17dbdf76e3d5 (diff)
pkg/compiler: allow unions with only 1 field
Unions with only 1 field are not actually unions, and can always be replaced with the option type. However, they are still useful when there will be more options in future but currently only 1 is described. Alternatives are: - not using union (but then all existing programs will be broken when union is finally introduced) - adding a fake field (ugly and reduces fuzzer efficiency) Allow unions with only 1 field.
Diffstat (limited to 'prog/mutation.go')
-rw-r--r--prog/mutation.go23
1 files changed, 17 insertions, 6 deletions
diff --git a/prog/mutation.go b/prog/mutation.go
index bdf83a128..7a401c854 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -195,14 +195,21 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
}
case *UnionType:
a := arg.(*UnionArg)
- optType := t.Fields[r.Intn(len(t.Fields))]
- maxIters := 1000
- for i := 0; optType.FieldName() == a.OptionType.FieldName(); i++ {
- optType = t.Fields[r.Intn(len(t.Fields))]
- if i >= maxIters {
- panic(fmt.Sprintf("couldn't generate a different union option after %v iterations, type: %+v", maxIters, t))
+ current := -1
+ for i, option := range t.Fields {
+ if a.Option.Type().FieldName() == option.FieldName() {
+ current = i
+ break
}
}
+ if current == -1 {
+ panic("can't find current option in union")
+ }
+ newIdx := r.Intn(len(t.Fields) - 1)
+ if newIdx >= current {
+ newIdx++
+ }
+ optType := t.Fields[newIdx]
p.removeArg(c, a.Option)
opt, calls := r.generateArg(s, optType)
arg1 := MakeUnionArg(t, opt, optType)
@@ -517,6 +524,10 @@ func (target *Target) mutationArgs(c *Call) (args, bases []Arg, parents []*[]Arg
return
}
// These special structs are mutated as a whole.
+ case *UnionType:
+ if len(typ.Fields) == 1 {
+ return
+ }
case *ArrayType:
// Don't mutate fixed-size arrays.
if typ.Kind == ArrayRangeLen && typ.RangeBegin == typ.RangeEnd {