From 1a85811d68e1f3870a4c71c170f014a8a5cc60b1 Mon Sep 17 00:00:00 2001 From: Dmitry Vyukov Date: Sat, 29 Oct 2016 10:24:21 +0200 Subject: prog: assign types to args during construction Eliminate assignTypeAndDir function and instead assign types to all args during construction. This will allow considerable simplifation of assignSizes. --- prog/analysis.go | 75 ++-------------------- prog/clone.go | 1 - prog/encoding.go | 30 ++++----- prog/mutation.go | 37 +++-------- prog/prog.go | 52 +++++++-------- prog/rand.go | 185 ++++++++++++++++++++++++++++++----------------------- prog/size_test.go | 3 - prog/validation.go | 11 ++-- 8 files changed, 165 insertions(+), 229 deletions(-) diff --git a/prog/analysis.go b/prog/analysis.go index 24f02903c..cecdd71d9 100644 --- a/prog/analysis.go +++ b/prog/analysis.go @@ -149,86 +149,23 @@ func foreachArg(c *Call, f func(arg, base *Arg, parent *[]*Arg)) { foreachArgArray(&c.Args, nil, f) } -func assignTypeAndDir(c *Call) error { - var rec func(arg *Arg, typ sys.Type) error - rec = func(arg *Arg, typ sys.Type) error { - if arg.Call != nil && arg.Call != c { - panic(fmt.Sprintf("different call is already assigned: %p %p %v %v", arg.Call, c, arg.Call.Meta.Name, c.Meta.Name)) - } - arg.Call = c - if arg.Type != nil && arg.Type.Name() != typ.Name() { - panic("different type is already assigned: " + arg.Type.Name() + " vs " + typ.Name()) - } - arg.Type = typ - switch arg.Kind { - case ArgPointer: - switch typ1 := typ.(type) { - case *sys.PtrType: - if arg.Res != nil { - if err := rec(arg.Res, typ1.Type); err != nil { - return err - } - } - } - case ArgGroup: - switch typ1 := typ.(type) { - case *sys.StructType: - if len(arg.Inner) != len(typ1.Fields) { - return fmt.Errorf("wrong struct field count: %v, want %v", len(arg.Inner), len(typ1.Fields)) - } - for i, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Fields[i]); err != nil { - return err - } - } - case *sys.ArrayType: - for _, arg1 := range arg.Inner { - if err := rec(arg1, typ1.Type); err != nil { - return err - } - } - } - case ArgUnion: - if err := rec(arg.Option, arg.OptionType); err != nil { - return err - } - default: - } - return nil - } - for i, arg := range c.Args { - if c.Meta == nil { - panic("nil meta") - } - if err := rec(arg, c.Meta.Args[i]); err != nil { - return err - } - } - if c.Ret == nil { - c.Ret = returnArg() - c.Ret.Call = c - c.Ret.Type = c.Meta.Ret - } - return nil -} - func generateSize(typ sys.Type, arg *Arg, lenType *sys.LenType) *Arg { if arg == nil { // Arg is an optional pointer, set size to 0. - return constArg(0) + return constArg(lenType, 0) } switch typ.(type) { case *sys.VmaType: - return pageSizeArg(arg.AddrPagesNum, 0) + return pageSizeArg(lenType, arg.AddrPagesNum, 0) case *sys.ArrayType: if lenType.ByteSize { - return constArg(arg.Size(typ)) + return constArg(lenType, arg.Size(typ)) } else { - return constArg(uintptr(len(arg.Inner))) + return constArg(lenType, uintptr(len(arg.Inner))) } default: - return constArg(arg.Size(typ)) + return constArg(lenType, arg.Size(typ)) } } @@ -271,7 +208,7 @@ func assignSizes(types []sys.Type, args []*Arg) { } if lenType.Buf == "parent" { - *lenArg = *constArg(parentSize) + *lenArg = *constArg(lenType, parentSize) continue } diff --git a/prog/clone.go b/prog/clone.go index 14f9db759..69a54cd4e 100644 --- a/prog/clone.go +++ b/prog/clone.go @@ -24,7 +24,6 @@ func (p *Prog) Clone() *Prog { func (arg *Arg) clone(c *Call, newargs map[*Arg]*Arg) *Arg { arg1 := new(Arg) *arg1 = *arg - arg1.Call = c arg1.Data = append([]byte{}, arg.Data...) switch arg.Kind { case ArgPointer: diff --git a/prog/encoding.go b/prog/encoding.go index d99f42f6f..7afe218be 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -137,7 +137,10 @@ func Deserialize(data []byte) (prog *Prog, err error) { if meta == nil { return nil, fmt.Errorf("unknown syscall %v", name) } - c := &Call{Meta: meta} + c := &Call{ + Meta: meta, + Ret: returnArg(meta.Ret), + } prog.Calls = append(prog.Calls, c) p.Parse('(') for i := 0; p.Char() != ')'; i++ { @@ -164,9 +167,6 @@ func Deserialize(data []byte) (prog *Prog, err error) { if len(c.Args) != len(meta.Args) { return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args)) } - if err := assignTypeAndDir(c); err != nil { - return nil, err - } if r != "" { vars[r] = c.Ret } @@ -196,14 +196,14 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, fmt.Errorf("wrong arg value '%v': %v", val, err) } - arg = constArg(uintptr(v)) + arg = constArg(typ, uintptr(v)) case 'r': id := p.Ident() v, ok := vars[id] if !ok || v == nil { return nil, fmt.Errorf("result %v references unknown variable (vars=%+v)", id, vars) } - arg = resultArg(v) + arg = resultArg(typ, v) if p.Char() == '/' { p.Parse('/') op := p.Ident() @@ -241,13 +241,13 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, err } - arg = pointerArg(page, off, size, inner) + arg = pointerArg(typ, page, off, size, inner) case '(': page, off, _, err := parseAddr(p, false) if err != nil { return nil, err } - arg = pageSizeArg(page, off) + arg = pageSizeArg(typ, page, off) case '"': p.Parse('"') val := "" @@ -259,7 +259,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, fmt.Errorf("data arg has bad value '%v'", val) } - arg = dataArg(data) + arg = dataArg(typ, data) case '{': t1, ok := typ.(*sys.StructType) if !ok { @@ -273,7 +273,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } fld := t1.Fields[i] if sys.IsPad(fld) { - inner = append(inner, constArg(0)) + inner = append(inner, constArg(fld, 0)) } else { arg, err := parseArg(fld, p, vars) if err != nil { @@ -286,10 +286,10 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } } p.Parse('}') - if sys.IsPad(t1.Fields[len(t1.Fields)-1]) { - inner = append(inner, constArg(0)) + if last := t1.Fields[len(t1.Fields)-1]; sys.IsPad(last) { + inner = append(inner, constArg(last, 0)) } - arg = groupArg(inner) + arg = groupArg(typ, inner) case '[': t1, ok := typ.(*sys.ArrayType) if !ok { @@ -308,7 +308,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { } } p.Parse(']') - arg = groupArg(inner) + arg = groupArg(typ, inner) case '@': t1, ok := typ.(*sys.UnionType) if !ok { @@ -331,7 +331,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) { if err != nil { return nil, err } - arg = unionArg(opt, optType) + arg = unionArg(typ, opt, optType) case 'n': p.Parse('n') p.Parse('i') diff --git a/prog/mutation.go b/prog/mutation.go index 1c16a6347..c014381d7 100644 --- a/prog/mutation.go +++ b/prog/mutation.go @@ -62,7 +62,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { switch a := arg.Type.(type) { case *sys.IntType, *sys.FlagsType, *sys.FileoffType, *sys.ResourceType, *sys.VmaType: arg1, calls1 := r.generateArg(s, arg.Type) - p.replaceArg(arg, arg1, calls1) + p.replaceArg(c, arg, arg1, calls1) case *sys.BufferType: switch a.Kind { case sys.BufferBlobRand, sys.BufferBlobRange: @@ -131,15 +131,13 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { } } for _, c1 := range calls { - assignTypeAndDir(c1) sanitizeCall(c1) } - assignTypeAndDir(c) sanitizeCall(c) p.insertBefore(c, calls) } else if count < uintptr(len(arg.Inner)) { for _, arg := range arg.Inner[count:] { - p.removeArg(arg) + p.removeArg(c, arg) } arg.Inner = arg.Inner[:count] } @@ -150,8 +148,8 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { if arg.Res != nil { size = arg.Res.Size(arg.Res.Type) } - arg1, calls1 := r.addr(s, size, arg.Res) - p.replaceArg(arg, arg1, calls1) + arg1, calls1 := r.addr(s, a, size, arg.Res) + p.replaceArg(c, arg, arg1, calls1) case *sys.StructType: ctor := isSpecialStruct(a) if ctor == nil { @@ -159,7 +157,7 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { } arg1, calls1 := ctor(r, s) for i, f := range arg1.Inner { - p.replaceArg(arg.Inner[i], f, calls1) + p.replaceArg(c, arg.Inner[i], f, calls1) calls1 = nil } case *sys.UnionType: @@ -167,10 +165,10 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { for optType.Name() == arg.OptionType.Name() { optType = a.Options[r.Intn(len(a.Options))] } - p.removeArg(arg.Option) + p.removeArg(c, arg.Option) opt, calls := r.generateArg(s, optType) - arg1 := unionArg(opt, optType) - p.replaceArg(arg, arg1, calls) + arg1 := unionArg(a, opt, optType) + p.replaceArg(c, arg, arg1, calls) case *sys.LenType: panic("bad arg returned by mutationArgs: LenType") case *sys.ConstType, *sys.StrConstType: @@ -181,9 +179,8 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { // Update base pointer if size has increased. if base != nil && baseSize < base.Res.Size(base.Res.Type) { - arg1, calls1 := r.addr(s, base.Res.Size(base.Res.Type), base.Res) + arg1, calls1 := r.addr(s, base.Type, base.Res.Size(base.Res.Type), base.Res) for _, c1 := range calls1 { - assignTypeAndDir(c1) sanitizeCall(c1) } p.insertBefore(c, calls1) @@ -194,8 +191,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { // Update all len fields. assignSizesCall(c) - // Assign Arg.Type fields for newly created len args. - assignTypeAndDir(c) } }, 1, func() { @@ -210,7 +205,6 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable) { ) } for _, c := range p.Calls { - assignTypeAndDir(c) sanitizeCall(c) } if err := p.validate(); err != nil { @@ -254,18 +248,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool) (*Prog, int) } } // Prepend uber-mmap. - mmap := &Call{ - Meta: sys.CallMap["mmap"], - Args: []*Arg{ - pointerArg(0, 0, uintptr(hi)+1, nil), - pageSizeArg(uintptr(hi)+1, 0), - constArg(sys.PROT_READ | sys.PROT_WRITE), - constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED), - constArg(sys.InvalidFD), - constArg(0), - }, - } - assignTypeAndDir(mmap) + mmap := createMmapCall(0, uintptr(hi)+1) p.Calls = append([]*Call{mmap}, p.Calls...) if callIndex != -1 { callIndex++ diff --git a/prog/prog.go b/prog/prog.go index 550b8416d..47c99b1d5 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -20,7 +20,6 @@ type Call struct { } type Arg struct { - Call *Call Type sys.Type Kind ArgKind Val uintptr // value of ArgConst @@ -131,12 +130,12 @@ func (a *Arg) Size(typ sys.Type) uintptr { } } -func constArg(v uintptr) *Arg { - return &Arg{Kind: ArgConst, Val: v} +func constArg(t sys.Type, v uintptr) *Arg { + return &Arg{Type: t, Kind: ArgConst, Val: v} } -func resultArg(r *Arg) *Arg { - arg := &Arg{Kind: ArgResult, Res: r} +func resultArg(t sys.Type, r *Arg) *Arg { + arg := &Arg{Type: t, Kind: ArgResult, Res: r} if r.Uses == nil { r.Uses = make(map[*Arg]bool) } @@ -147,28 +146,28 @@ func resultArg(r *Arg) *Arg { return arg } -func dataArg(data []byte) *Arg { - return &Arg{Kind: ArgData, Data: append([]byte{}, data...)} +func dataArg(t sys.Type, data []byte) *Arg { + return &Arg{Type: t, Kind: ArgData, Data: append([]byte{}, data...)} } -func pointerArg(page uintptr, off int, npages uintptr, obj *Arg) *Arg { - return &Arg{Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj} +func pointerArg(t sys.Type, page uintptr, off int, npages uintptr, obj *Arg) *Arg { + return &Arg{Type: t, Kind: ArgPointer, AddrPage: page, AddrOffset: off, AddrPagesNum: npages, Res: obj} } -func pageSizeArg(npages uintptr, off int) *Arg { - return &Arg{Kind: ArgPageSize, AddrPage: npages, AddrOffset: off} +func pageSizeArg(t sys.Type, npages uintptr, off int) *Arg { + return &Arg{Type: t, Kind: ArgPageSize, AddrPage: npages, AddrOffset: off} } -func groupArg(inner []*Arg) *Arg { - return &Arg{Kind: ArgGroup, Inner: inner} +func groupArg(t sys.Type, inner []*Arg) *Arg { + return &Arg{Type: t, Kind: ArgGroup, Inner: inner} } -func unionArg(opt *Arg, typ sys.Type) *Arg { - return &Arg{Kind: ArgUnion, Option: opt, OptionType: typ} +func unionArg(t sys.Type, opt *Arg, typ sys.Type) *Arg { + return &Arg{Type: t, Kind: ArgUnion, Option: opt, OptionType: typ} } -func returnArg() *Arg { - return &Arg{Kind: ArgReturn} +func returnArg(t sys.Type) *Arg { + return &Arg{Type: t, Kind: ArgReturn} } func (p *Prog) insertBefore(c *Call, calls []*Call) { @@ -188,8 +187,8 @@ func (p *Prog) insertBefore(c *Call, calls []*Call) { p.Calls = newCalls } -// replaceArg replaces arg with arg1 in p, and inserts calls before arg call. -func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { +// replaceArg replaces arg with arg1 in call c in program p, and inserts calls before arg call. +func (p *Prog) replaceArg(c *Call, arg, arg1 *Arg, calls []*Call) { if arg.Kind != ArgConst && arg.Kind != ArgResult && arg.Kind != ArgPointer && arg.Kind != ArgUnion { panic(fmt.Sprintf("replaceArg: bad arg kind %v", arg.Kind)) } @@ -200,10 +199,8 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { delete(arg.Res.Uses, arg) } for _, c := range calls { - assignTypeAndDir(c) sanitizeCall(c) } - c := arg.Call p.insertBefore(c, calls) // Somewhat hacky, but safe and preserves references to arg. uses := arg.Uses @@ -213,12 +210,11 @@ func (p *Prog) replaceArg(arg, arg1 *Arg, calls []*Call) { delete(arg.Res.Uses, arg1) arg.Res.Uses[arg] = true } - assignTypeAndDir(c) sanitizeCall(c) } -// removeArg removes all references to/from arg0 from p. -func (p *Prog) removeArg(arg0 *Arg) { +// removeArg removes all references to/from arg0 of call c from p. +func (p *Prog) removeArg(c *Call, arg0 *Arg) { foreachSubarg(arg0, func(arg, _ *Arg, _ *[]*Arg) { if arg.Kind == ArgResult { if _, ok := arg.Res.Uses[arg]; !ok { @@ -230,8 +226,8 @@ func (p *Prog) removeArg(arg0 *Arg) { if arg1.Kind != ArgResult { panic("use references not ArgResult") } - arg2 := constArg(arg1.Type.Default()) - p.replaceArg(arg1, arg2, nil) + arg2 := constArg(arg1.Type, arg1.Type.Default()) + p.replaceArg(c, arg1, arg2, nil) } }) } @@ -242,7 +238,7 @@ func (p *Prog) removeCall(idx int) { copy(p.Calls[idx:], p.Calls[idx+1:]) p.Calls = p.Calls[:len(p.Calls)-1] for _, arg := range c.Args { - p.removeArg(arg) + p.removeArg(c, arg) } - p.removeArg(c.Ret) + p.removeArg(c, c.Ret) } diff --git a/prog/rand.go b/prog/rand.go index 49c1ed193..d9c607a6d 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -193,25 +193,25 @@ func (r *randGen) inport(s *state) uint16 { return uint16(r.Intn(20))<<8 + 0xab } -func (r *randGen) in6addr(s *state) (arg *Arg, calls []*Call) { +func (r *randGen) in6addr(s *state, typ sys.Type) (arg *Arg, calls []*Call) { // addr: loopback (big endian) - return groupArg([]*Arg{ - constArg(0), - constArg(0), - constArg(0), - constArg(1 << 24), + return groupArg(typ, []*Arg{ + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 1<<24), }), nil } -func (r *randGen) inaddrany(s *state) (arg *Arg, calls []*Call) { +func (r *randGen) inaddrany(s *state, typ sys.Type) (arg *Arg, calls []*Call) { if r.bin() { - return r.in6addr(s) + return r.in6addr(s, typ) } else { - return groupArg([]*Arg{ - constArg(uintptr(r.inaddr(s))), - constArg(0), - constArg(0), - constArg(0), + return groupArg(typ, []*Arg{ + constArg(nil, uintptr(r.inaddr(s))), + constArg(nil, 0), + constArg(nil, 0), + constArg(nil, 0), }), nil } } @@ -331,38 +331,42 @@ func (r *randGen) algName(s *state) []byte { } func isSpecialStruct(typ sys.Type) func(r *randGen, s *state) (*Arg, []*Call) { - if _, ok := typ.(*sys.StructType); !ok { + a, ok := typ.(*sys.StructType) + if !ok { panic("must be a struct") } switch typ.Name() { case "timespec": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.timespec(s, false) + return r.timespec(s, a, false) } case "timeval": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.timespec(s, true) + return r.timespec(s, a, true) } case "in6_addr": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.in6addr(s) + return r.in6addr(s, a) } case "in_addr_any": return func(r *randGen, s *state) (*Arg, []*Call) { - return r.inaddrany(s) + return r.inaddrany(s, a) } } return nil } -func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) { +func (r *randGen) timespec(s *state, typ *sys.StructType, usec bool) (arg *Arg, calls []*Call) { // We need to generate timespec/timeval that are either (1) definitely in the past, // or (2) definitely in unreachable fututre, or (3) few ms ahead of now. // Note timespec/timeval can be absolute or relative to now. r.choose( 1, func() { // now for relative, past for absolute - arg = groupArg([]*Arg{constArg(0), constArg(0)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 0), + constArg(typ.Fields[1], 0), + }) }, 1, func() { // few ms ahead for relative, past for absolute @@ -370,46 +374,77 @@ func (r *randGen) timespec(s *state, usec bool) (arg *Arg, calls []*Call) { if usec { nsec /= 1e3 } - arg = groupArg([]*Arg{constArg(0), constArg(nsec)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 0), + constArg(typ.Fields[1], nsec), + }) }, 1, func() { // unreachable fututre for both relative and absolute - arg = groupArg([]*Arg{constArg(2e9), constArg(0)}) + arg = groupArg(typ, []*Arg{ + constArg(typ.Fields[0], 2e9), + constArg(typ.Fields[1], 0), + }) }, 1, func() { // few ms ahead for absolute - tp := groupArg([]*Arg{constArg(0), constArg(0)}) + meta := sys.CallMap["clock_gettime"] + ptrArgType := meta.Args[1].(*sys.PtrType) + argType := ptrArgType.Type.(*sys.StructType) + tp := groupArg(argType, []*Arg{ + constArg(argType.Fields[0], 0), + constArg(argType.Fields[1], 0), + }) var tpaddr *Arg - tpaddr, calls = r.addr(s, 2*ptrSize, tp) + tpaddr, calls = r.addr(s, ptrArgType, 2*ptrSize, tp) gettime := &Call{ - Meta: sys.CallMap["clock_gettime"], + Meta: meta, Args: []*Arg{ - constArg(sys.CLOCK_REALTIME), + constArg(meta.Args[0], sys.CLOCK_REALTIME), tpaddr, }, + Ret: returnArg(meta.Ret), } calls = append(calls, gettime) - sec := resultArg(tp.Inner[0]) - nsec := resultArg(tp.Inner[1]) + sec := resultArg(typ.Fields[0], tp.Inner[0]) + nsec := resultArg(typ.Fields[1], tp.Inner[1]) if usec { nsec.OpDiv = 1e3 nsec.OpAdd = 10 * 1e3 } else { nsec.OpAdd = 10 * 1e6 } - arg = groupArg([]*Arg{sec, nsec}) + arg = groupArg(typ, []*Arg{sec, nsec}) }, ) return } -func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) { +// createMmapCall creates a "normal" mmap call that maps [start, start+npages) page range. +func createMmapCall(start, npages uintptr) *Call { + meta := sys.CallMap["mmap"] + mmap := &Call{ + Meta: meta, + Args: []*Arg{ + pointerArg(meta.Args[0], start, 0, npages, nil), + pageSizeArg(meta.Args[1], npages, 0), + constArg(meta.Args[2], sys.PROT_READ|sys.PROT_WRITE), + constArg(meta.Args[3], sys.MAP_ANONYMOUS|sys.MAP_PRIVATE|sys.MAP_FIXED), + constArg(meta.Args[4], sys.InvalidFD), + constArg(meta.Args[5], 0), + }, + Ret: returnArg(meta.Ret), + } + return mmap +} + +func (r *randGen) addr1(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) { npages := (size + pageSize - 1) / pageSize if npages == 0 { npages = 1 } if r.oneOf(10) { - return r.randPageAddr(s, npages, data, false), nil + return r.randPageAddr(s, typ, npages, data, false), nil } for i := uintptr(0); i < maxPages-npages; i++ { free := true @@ -422,24 +457,14 @@ func (r *randGen) addr1(s *state, size uintptr, data *Arg) (*Arg, []*Call) { if !free { continue } - c := &Call{ - Meta: sys.CallMap["mmap"], - Args: []*Arg{ - pointerArg(i, 0, npages, nil), - pageSizeArg(npages, 0), - constArg(sys.PROT_READ | sys.PROT_WRITE), - constArg(sys.MAP_ANONYMOUS | sys.MAP_PRIVATE | sys.MAP_FIXED), - constArg(sys.InvalidFD), - constArg(0), - }, - } - return pointerArg(i, 0, 0, data), []*Call{c} + c := createMmapCall(i, npages) + return pointerArg(typ, i, 0, 0, data), []*Call{c} } - return r.randPageAddr(s, npages, data, false), nil + return r.randPageAddr(s, typ, npages, data, false), nil } -func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) { - arg, calls := r.addr1(s, size, data) +func (r *randGen) addr(s *state, typ sys.Type, size uintptr, data *Arg) (*Arg, []*Call) { + arg, calls := r.addr1(s, typ, size, data) if arg.Kind != ArgPointer { panic("bad") } @@ -457,7 +482,7 @@ func (r *randGen) addr(s *state, size uintptr, data *Arg) (*Arg, []*Call) { return arg, calls } -func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *Arg { +func (r *randGen) randPageAddr(s *state, typ sys.Type, npages uintptr, data *Arg, vma bool) *Arg { var starts []uintptr for i := uintptr(0); i < maxPages-npages; i++ { busy := true @@ -483,13 +508,13 @@ func (r *randGen) randPageAddr(s *state, npages uintptr, data *Arg, vma bool) *A if !vma { npages = 0 } - return pointerArg(page, 0, npages, data) + return pointerArg(typ, page, 0, npages, data) } func (r *randGen) createResource(s *state, res *sys.ResourceType) (arg *Arg, calls []*Call) { if r.inCreateResource { special := res.SpecialValues() - return constArg(special[r.Intn(len(special))]), nil + return constArg(res, special[r.Intn(len(special))]), nil } r.inCreateResource = true defer func() { r.inCreateResource = false }() @@ -516,7 +541,7 @@ func (r *randGen) createResource(s *state, res *sys.ResourceType) (arg *Arg, cal metas = append(metas, meta) } if len(metas) == 0 { - return constArg(res.Default()), nil + return constArg(res, res.Default()), nil } // Now we have a set of candidate calls that can create the necessary resource. @@ -535,7 +560,7 @@ func (r *randGen) createResource(s *state, res *sys.ResourceType) (arg *Arg, cal } if len(allres) != 0 { // Bingo! - arg := resultArg(allres[r.Intn(len(allres))]) + arg := resultArg(res, allres[r.Intn(len(allres))]) return arg, calls } switch meta.Name { @@ -599,11 +624,13 @@ func (r *randGen) generateCall(s *state, p *Prog) []*Call { } func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Call) { - c := &Call{Meta: meta} + c := &Call{ + Meta: meta, + Ret: returnArg(meta.Ret), + } c.Args, calls = r.generateArgs(s, meta.Args) calls = append(calls, c) for _, c1 := range calls { - assignTypeAndDir(c1) sanitizeCall(c1) } return calls @@ -637,7 +664,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) switch typ.(type) { case *sys.IntType, *sys.FlagsType, *sys.ConstType, *sys.StrConstType, *sys.FileoffType, *sys.ResourceType, *sys.VmaType: - return constArg(0), nil + return constArg(typ, 0), nil } } @@ -645,7 +672,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) if _, ok := typ.(*sys.BufferType); ok { panic("impossible") // parent PtrType must be Optional instead } - return constArg(typ.Default()), nil + return constArg(typ, typ.Default()), nil } switch a := typ.(type) { @@ -653,7 +680,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) r.choose( 1, func() { special := a.SpecialValues() - arg = constArg(special[r.Intn(len(special))]) + arg = constArg(a, special[r.Intn(len(special))]) }, 90, func() { // Get an existing resource. @@ -665,7 +692,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) } } if len(allres) != 0 { - arg = resultArg(allres[r.Intn(len(allres))]) + arg = resultArg(a, allres[r.Intn(len(allres))]) } else { arg, calls = r.createResource(s, a) } @@ -680,9 +707,9 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) // TODO: can do better var arg *Arg r.choose( - 90, func() { arg = constArg(0) }, - 10, func() { arg = constArg(r.rand(100)) }, - 1, func() { arg = constArg(r.randInt()) }, + 90, func() { arg = constArg(a, 0) }, + 10, func() { arg = constArg(a, r.rand(100)) }, + 1, func() { arg = constArg(a, r.randInt()) }, ) return arg, nil case *sys.BufferType: @@ -698,13 +725,13 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) data[i] = byte(r.Intn(256)) } } - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferString: data := r.randString(s) - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferFilesystem: data := r.filesystem(s) - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferSockaddr: data := r.sockaddr(s) if a.Dir() == sys.DirOut { @@ -712,7 +739,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) data[i] = 0 } } - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferAlgType: data := r.algType(s) if a.Dir() == sys.DirOut { @@ -720,7 +747,7 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) data[i] = 0 } } - return dataArg(data), nil + return dataArg(a, data), nil case sys.BufferAlgName: data := r.algName(s) if a.Dir() == sys.DirOut { @@ -728,20 +755,20 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) data[i] = 0 } } - return dataArg(data), nil + return dataArg(a, data), nil default: panic("unknown buffer kind") } case *sys.VmaType: npages := r.randPageCount() - arg := r.randPageAddr(s, npages, nil, true) + arg := r.randPageAddr(s, a, npages, nil, true) return arg, nil case *sys.FlagsType: - return constArg(r.flags(a.Vals)), nil + return constArg(a, r.flags(a.Vals)), nil case *sys.ConstType: - return constArg(a.Val), nil + return constArg(a, a.Val), nil case *sys.StrConstType: - return dataArg([]byte(a.Val)), nil + return dataArg(a, []byte(a.Val)), nil case *sys.IntType: v := r.randInt() switch a.Kind { @@ -754,10 +781,10 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) case sys.IntRange: v = r.randRangeInt(a.RangeBegin, a.RangeEnd) } - return constArg(v), nil + return constArg(a, v), nil case *sys.FilenameType: filename := r.filename(s) - return dataArg([]byte(filename)), nil + return dataArg(a, []byte(filename)), nil case *sys.ArrayType: count := uintptr(0) switch a.Kind { @@ -773,24 +800,24 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) inner = append(inner, arg1) calls = append(calls, calls1...) } - return groupArg(inner), calls + return groupArg(a, inner), calls case *sys.StructType: if ctor := isSpecialStruct(a); ctor != nil && a.Dir() != sys.DirOut { arg, calls = ctor(r, s) return } args, calls := r.generateArgs(s, a.Fields) - group := groupArg(args) + group := groupArg(a, args) return group, calls case *sys.UnionType: optType := a.Options[r.Intn(len(a.Options))] opt, calls := r.generateArg(s, optType) - return unionArg(opt, optType), calls + return unionArg(a, opt, optType), calls case *sys.PtrType: inner, calls := r.generateArg(s, a.Type) if a.Dir() == sys.DirOut && inner == nil { // No data, but we should have got size. - arg, calls1 := r.addr(s, inner.Size(a.Type), nil) + arg, calls1 := r.addr(s, a, inner.Size(a.Type), nil) calls = append(calls, calls1...) return arg, calls } @@ -799,15 +826,15 @@ func (r *randGen) generateArg(s *state, typ sys.Type) (arg *Arg, calls []*Call) // So try to reuse a previously used address. addrs := s.resources["iocbptr"] addr := addrs[r.Intn(len(addrs))] - arg = pointerArg(addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner) + arg = pointerArg(a, addr.AddrPage, addr.AddrOffset, addr.AddrPagesNum, inner) return arg, calls } - arg, calls1 := r.addr(s, inner.Size(a.Type), inner) + arg, calls1 := r.addr(s, a, inner.Size(a.Type), inner) calls = append(calls, calls1...) return arg, calls case *sys.LenType: // Return placeholder value of 0 while generating len args. - return constArg(0), nil + return constArg(a, 0), nil default: panic("unknown argument type") } diff --git a/prog/size_test.go b/prog/size_test.go index 41068e713..ad1ba8740 100644 --- a/prog/size_test.go +++ b/prog/size_test.go @@ -16,7 +16,6 @@ func TestAssignSizeRandom(t *testing.T) { data0 := p.Serialize() for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } if data1 := p.Serialize(); !bytes.Equal(data0, data1) { t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1) @@ -26,7 +25,6 @@ func TestAssignSizeRandom(t *testing.T) { data0 := p.Serialize() for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } if data1 := p.Serialize(); !bytes.Equal(data0, data1) { t.Fatalf("different lens assigned, initial: %v, new: %v", data0, data1) @@ -113,7 +111,6 @@ func TestAssignSize(t *testing.T) { } for _, call := range p.Calls { assignSizesCall(call) - assignTypeAndDir(call) } p1 := strings.TrimSpace(string(p.Serialize())) if p1 != test.sizedProg { diff --git a/prog/validation.go b/prog/validation.go index 998581e28..1628e38fa 100644 --- a/prog/validation.go +++ b/prog/validation.go @@ -41,9 +41,6 @@ func (c *Call) validate(ctx *validCtx) error { if arg == nil { return fmt.Errorf("syscall %v: nil arg", c.Meta.Name) } - if arg.Call != c { - return fmt.Errorf("syscall %v: arg has wrong call, call=%p, arg=%+v", c.Meta.Name, c, *arg) - } if ctx.args[arg] { return fmt.Errorf("syscall %v: arg is referenced several times in the tree", c.Meta.Name) } @@ -55,7 +52,7 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: no type", c.Meta.Name) } if arg.Type.Name() != typ.Name() { - return fmt.Errorf("syscall %v: arg '%v' type mismatch", c.Meta.Name, typ.Name()) + return fmt.Errorf("syscall %v: type name mismatch: %v vs %v", c.Meta.Name, arg.Type.Name(), typ.Name()) } if arg.Type.Dir() == sys.DirOut { if arg.Val != 0 || arg.AddrPage != 0 || arg.AddrOffset != 0 { @@ -105,8 +102,8 @@ func (c *Call) validate(ctx *validCtx) error { return fmt.Errorf("syscall %v: result arg '%v' has no reference", c.Meta.Name, typ.Name()) } if !ctx.args[arg.Res] { - return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %v %p%+v", - c.Meta.Name, typ.Name(), arg, arg, arg.Res.Call.Meta.Name, arg.Res, arg.Res) + return fmt.Errorf("syscall %v: result arg '%v' references out-of-tree result: %p%+v -> %p%+v", + c.Meta.Name, typ.Name(), arg, arg, arg.Res, arg.Res) } if _, ok := arg.Res.Uses[arg]; !ok { return fmt.Errorf("syscall %v: result arg '%v' has broken link (%+v)", c.Meta.Name, typ.Name(), arg.Res.Uses) @@ -185,7 +182,7 @@ func (c *Call) validate(ctx *validCtx) error { return nil } for i, arg := range c.Args { - if c.Ret.Kind != ArgReturn { + if arg.Kind == ArgReturn { return fmt.Errorf("syscall %v: arg '%v' has wrong return kind", c.Meta.Name, arg.Type.Name()) } if err := checkArg(arg, c.Meta.Args[i]); err != nil { -- cgit mrf-deployment