diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-02-18 13:49:48 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-02-19 21:48:20 +0100 |
| commit | 85d1218f4108e0fe793f63e57e2edadd5da5764f (patch) | |
| tree | 2b8cbd8c476cd0f21d1add6bc74d0ca5bb9dec46 /prog/mutation.go | |
| parent | 2be2288ee256f3b84a7de15b82894097a08fd939 (diff) | |
prog: rework foreachArg
Make Foreach* callback accept the arg and a context struct
that can contain lots of aux info.
This (1) removes lots of unuser base/parent args,
(2) provides foundation for stopping recursion,
(3) allows to merge foreachSubargOffset.
Diffstat (limited to 'prog/mutation.go')
| -rw-r--r-- | prog/mutation.go | 62 |
1 files changed, 28 insertions, 34 deletions
diff --git a/prog/mutation.go b/prog/mutation.go index 0aa06979e..83d73a501 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -67,14 +67,14 @@ outer: retryArg := false for stop := false; !stop || retryArg; stop = r.oneOf(3) { retryArg = false - args, bases, parents := p.Target.mutationArgs(c) + args, ctxes := p.Target.mutationArgs(c) if len(args) == 0 { retry = true continue outer } idx := r.Intn(len(args)) - arg, base, parent := args[idx], bases[idx], parents[idx] - calls, ok := p.Target.mutateArg(r, s, arg, base, parent, &updateSizes) + arg, ctx := args[idx], ctxes[idx] + calls, ok := p.Target.mutateArg(r, s, arg, ctx, &updateSizes) if !ok { retryArg = true continue @@ -106,14 +106,10 @@ outer: } } -func (target *Target) mutateArg(r *randGen, s *state, arg, base Arg, parent *[]Arg, updateSizes *bool) (calls []*Call, ok bool) { +func (target *Target) mutateArg(r *randGen, s *state, arg Arg, ctx ArgCtx, updateSizes *bool) (calls []*Call, ok bool) { var baseSize uint64 - if base != nil { - b, ok := base.(*PointerArg) - if !ok || b.Res == nil { - panic("bad base arg") - } - baseSize = b.Res.Size() + if ctx.Base != nil { + baseSize = ctx.Base.Res.Size() } switch t := arg.Type().(type) { case *IntType, *FlagsType: @@ -133,7 +129,7 @@ func (target *Target) mutateArg(r *randGen, s *state, arg, base Arg, parent *[]A } } case *LenType: - if !r.mutateSize(arg.(*ConstArg), *parent) { + if !r.mutateSize(arg.(*ConstArg), *ctx.Parent) { return nil, false } *updateSizes = false @@ -261,15 +257,14 @@ func (target *Target) mutateArg(r *randGen, s *state, arg, base Arg, parent *[]A } // Update base pointer if size has increased. - if base != nil { - b := base.(*PointerArg) - if baseSize < b.Res.Size() { - newArg, newCalls := r.addr(s, b.Type(), b.Res.Size(), b.Res) + if base := ctx.Base; base != nil { + if baseSize < base.Res.Size() { + newArg, newCalls := r.addr(s, base.Type(), base.Res.Size(), base.Res) calls = append(calls, newCalls...) a1 := newArg.(*PointerArg) - b.PageIndex = a1.PageIndex - b.PageOffset = a1.PageOffset - b.PagesNum = a1.PagesNum + base.PageIndex = a1.PageIndex + base.PageOffset = a1.PageOffset + base.PagesNum = a1.PagesNum } } for _, c := range calls { @@ -278,29 +273,27 @@ func (target *Target) mutateArg(r *randGen, s *state, arg, base Arg, parent *[]A return calls, true } -func (target *Target) mutationSubargs(arg0 Arg) (args, bases []Arg, parents []*[]Arg) { - ForeachSubarg(arg0, func(arg, base Arg, parent *[]Arg) { - if target.needMutateArg(arg, base, parent) { +func (target *Target) mutationSubargs(arg0 Arg) (args []Arg, ctxes []ArgCtx) { + ForeachSubArg(arg0, func(arg Arg, ctx *ArgCtx) { + if target.needMutateArg(arg, ctx) { args = append(args, arg) - bases = append(bases, base) - parents = append(parents, parent) + ctxes = append(ctxes, *ctx) } }) return } -func (target *Target) mutationArgs(c *Call) (args, bases []Arg, parents []*[]Arg) { - foreachArg(c, func(arg, base Arg, parent *[]Arg) { - if target.needMutateArg(arg, base, parent) { +func (target *Target) mutationArgs(c *Call) (args []Arg, ctxes []ArgCtx) { + ForeachArg(c, func(arg Arg, ctx *ArgCtx) { + if target.needMutateArg(arg, ctx) { args = append(args, arg) - bases = append(bases, base) - parents = append(parents, parent) + ctxes = append(ctxes, *ctx) } }) return } -func (target *Target) needMutateArg(arg, base Arg, parent *[]Arg) bool { +func (target *Target) needMutateArg(arg Arg, ctx *ArgCtx) bool { switch typ := arg.Type().(type) { case *StructType: if target.SpecialTypes[typ.Name()] == nil { @@ -329,20 +322,21 @@ func (target *Target) needMutateArg(arg, base Arg, parent *[]Arg) bool { } } typ := arg.Type() - if typ.Dir() == DirOut || !typ.Varlen() && typ.Size() == 0 { + if typ == nil || typ.Dir() == DirOut || !typ.Varlen() && typ.Size() == 0 { return false } - if base != nil { + if ctx.Base != nil { // TODO(dvyukov): need to check parent as well. // Say, timespec can be part of another struct and base // will point to that other struct, not timespec. // Strictly saying, we need to check parents all way up, // or better bail out from recursion when we reach // a special struct. - _, isStruct := base.Type().(*StructType) - _, isUnion := base.Type().(*UnionType) + baseType := ctx.Base.Type() + _, isStruct := baseType.(*StructType) + _, isUnion := baseType.(*UnionType) if (isStruct || isUnion) && - target.SpecialTypes[base.Type().Name()] != nil { + target.SpecialTypes[baseType.Name()] != nil { // These special structs/unions are mutated as a whole. return false } |
