aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2016-10-29 10:24:21 +0200
committerDmitry Vyukov <dvyukov@google.com>2016-11-11 14:29:52 -0800
commit1a85811d68e1f3870a4c71c170f014a8a5cc60b1 (patch)
tree5920f2684a99204ce255cfcb1fd4e9a3acdd6514 /prog
parentc35c72f06c58f0b40980b0410c8a0fd513c3a892 (diff)
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.
Diffstat (limited to 'prog')
-rw-r--r--prog/analysis.go75
-rw-r--r--prog/clone.go1
-rw-r--r--prog/encoding.go30
-rw-r--r--prog/mutation.go37
-rw-r--r--prog/prog.go52
-rw-r--r--prog/rand.go185
-rw-r--r--prog/size_test.go3
-rw-r--r--prog/validation.go11
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 {