diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-01-26 12:34:02 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-01-27 17:08:43 +0100 |
| commit | e8b49705479678b38c0068e84f1f599af8829184 (patch) | |
| tree | 4010754d8153c508159c24fe6ac2caeddaf4f284 /prog/mutation.go | |
| parent | 1d18b11287c0248782efe867659c17dbdf76e3d5 (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.go | 23 |
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 { |
