aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@gmail.com>2017-01-23 18:15:39 +0100
committerGitHub <noreply@github.com>2017-01-23 18:15:39 +0100
commitbb1ff0b5592262d20e88397f56f18e48d47d56ea (patch)
tree6eb2d4bd3090f730f9b91fddd38e2726f1a31034 /prog
parentcd23722cf2dabd28d83fa321c3cbf50a956d3fb7 (diff)
parent07880f3c010a2a5d4078b8668e05a4894fd82046 (diff)
Merge pull request #113 from xairy/parent-parent
Make it possible to specify length of parent of parent
Diffstat (limited to 'prog')
-rw-r--r--prog/analysis.go56
-rw-r--r--prog/encoding.go4
-rw-r--r--prog/mutation.go10
-rw-r--r--prog/rand.go3
-rw-r--r--prog/size_test.go6
-rw-r--r--prog/validation.go3
6 files changed, 58 insertions, 24 deletions
diff --git a/prog/analysis.go b/prog/analysis.go
index a4f399f98..81c17c9ee 100644
--- a/prog/analysis.go
+++ b/prog/analysis.go
@@ -174,18 +174,14 @@ func generateSize(arg *Arg, lenType *sys.LenType) *Arg {
}
}
-func assignSizes(args []*Arg) {
+func assignSizes(args []*Arg, parentsMap map[*Arg]*Arg) {
// Create a map of args and calculate size of the whole struct.
argsMap := make(map[string]*Arg)
- var parentSize uintptr
for _, arg := range args {
- if arg.Type.BitfieldLength() == 0 || arg.Type.BitfieldLast() {
- parentSize += arg.Size()
- }
if sys.IsPad(arg.Type) {
continue
}
- argsMap[arg.Type.Name()] = arg
+ argsMap[arg.Type.FieldName()] = arg
}
// Fill in size arguments.
@@ -194,32 +190,60 @@ func assignSizes(args []*Arg) {
continue // Pointer to optional len field, no need to fill in value.
}
if typ, ok := arg.Type.(*sys.LenType); ok {
+ buf, ok := argsMap[typ.Buf]
+ if ok {
+ *arg = *generateSize(buf.InnerArg(), typ)
+ continue
+ }
+
if typ.Buf == "parent" {
- arg.Val = parentSize
+ arg.Val = parentsMap[arg].Size()
if typ.ByteSize != 0 {
arg.Val /= typ.ByteSize
}
continue
}
- buf, ok := argsMap[typ.Buf]
- if !ok {
- panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
- typ.Name(), typ.Buf, argsMap))
+ sizeAssigned := false
+ for parent := parentsMap[arg]; parent != nil; parent = parentsMap[parent] {
+ if typ.Buf == parent.Type.Name() {
+ arg.Val = parent.Size()
+ if typ.ByteSize != 0 {
+ arg.Val /= typ.ByteSize
+ }
+ sizeAssigned = true
+ break
+ }
+ }
+ if sizeAssigned {
+ continue
}
- *arg = *generateSize(buf.InnerArg(), typ)
+ panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
+ typ.FieldName(), typ.Buf, argsMap))
}
}
}
-func assignSizesCall(c *Call) {
- assignSizes(c.Args)
- foreachArg(c, func(arg, base *Arg, parent *[]*Arg) {
+func assignSizesArray(args []*Arg) {
+ parentsMap := make(map[*Arg]*Arg)
+ foreachArgArray(&args, nil, func(arg, base *Arg, _ *[]*Arg) {
if _, ok := arg.Type.(*sys.StructType); ok {
- assignSizes(arg.Inner)
+ for _, field := range arg.Inner {
+ parentsMap[field.InnerArg()] = arg
+ }
}
})
+ assignSizes(args, parentsMap)
+ foreachArgArray(&args, nil, func(arg, base *Arg, _ *[]*Arg) {
+ if _, ok := arg.Type.(*sys.StructType); ok {
+ assignSizes(arg.Inner, parentsMap)
+ }
+ })
+}
+
+func assignSizesCall(c *Call) {
+ assignSizesArray(c.Args)
}
func sanitizeCall(c *Call) {
diff --git a/prog/encoding.go b/prog/encoding.go
index 8c7c1674a..274e94a2d 100644
--- a/prog/encoding.go
+++ b/prog/encoding.go
@@ -108,7 +108,7 @@ func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
}
buf.Write([]byte{delims[1]})
case ArgUnion:
- fmt.Fprintf(buf, "@%v=", a.OptionType.Name())
+ fmt.Fprintf(buf, "@%v=", a.OptionType.FieldName())
a.Option.serialize(buf, vars, varSeq)
default:
panic("unknown arg kind")
@@ -318,7 +318,7 @@ func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
p.Parse('=')
var optType sys.Type
for _, t2 := range t1.Options {
- if name == t2.Name() {
+ if name == t2.FieldName() {
optType = t2
break
}
diff --git a/prog/mutation.go b/prog/mutation.go
index 2136c86f8..9841d31ca 100644
--- a/prog/mutation.go
+++ b/prog/mutation.go
@@ -184,8 +184,12 @@ func (p *Prog) Mutate(rs rand.Source, ncalls int, ct *ChoiceTable, corpus []*Pro
}
case *sys.UnionType:
optType := a.Options[r.Intn(len(a.Options))]
- for optType.Name() == arg.OptionType.Name() {
+ maxIters := 1000
+ for i := 0; optType.FieldName() == arg.OptionType.FieldName(); i++ {
optType = a.Options[r.Intn(len(a.Options))]
+ if i >= maxIters {
+ panic(fmt.Sprintf("couldn't generate a different union option after %v iterations, type: %+v", maxIters, a))
+ }
}
p.removeArg(c, arg.Option)
opt, calls := r.generateArg(s, optType)
@@ -303,7 +307,7 @@ func Minimize(p0 *Prog, callIndex0 int, pred func(*Prog, int) bool, crash bool)
var rec func(p *Prog, call *Call, arg *Arg, path string) bool
rec = func(p *Prog, call *Call, arg *Arg, path string) bool {
- path += fmt.Sprintf("-%v", arg.Type.Name())
+ path += fmt.Sprintf("-%v", arg.Type.FieldName())
switch typ := arg.Type.(type) {
case *sys.StructType:
for _, innerArg := range arg.Inner {
@@ -438,7 +442,7 @@ func (p *Prog) TrimAfter(idx int) {
}
func mutationArgs(c *Call) (args, bases []*Arg) {
- foreachArg(c, func(arg, base *Arg, parent *[]*Arg) {
+ foreachArg(c, func(arg, base *Arg, _ *[]*Arg) {
switch typ := arg.Type.(type) {
case *sys.StructType:
if isSpecialStruct(typ) == nil {
diff --git a/prog/rand.go b/prog/rand.go
index 4645db811..4a7bbe08d 100644
--- a/prog/rand.go
+++ b/prog/rand.go
@@ -557,6 +557,7 @@ func (r *randGen) generateParticularCall(s *state, meta *sys.Call) (calls []*Cal
Ret: returnArg(meta.Ret),
}
c.Args, calls = r.generateArgs(s, meta.Args)
+ assignSizesCall(c)
calls = append(calls, c)
for _, c1 := range calls {
sanitizeCall(c1)
@@ -601,8 +602,6 @@ func (r *randGen) generateArgs(s *state, types []sys.Type) ([]*Arg, []*Call) {
calls = append(calls, calls1...)
}
- assignSizes(args)
-
return args, calls
}
diff --git a/prog/size_test.go b/prog/size_test.go
index 0b7e5fb98..f6e4ab17c 100644
--- a/prog/size_test.go
+++ b/prog/size_test.go
@@ -72,7 +72,7 @@ func TestAssignSize(t *testing.T) {
},
{
"syz_test$length8(&(0x7f000001f000)={0x00, {0xff, 0x0, 0x00, [0xff, 0xff, 0xff]}, [{0xff, 0x0, 0x00, [0xff, 0xff, 0xff]}], 0x00, 0x0, [0xff, 0xff]})",
- "syz_test$length8(&(0x7f000001f000)={0x32, {0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}, [{0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}], 0x10, 0x1, [0xff, 0xff]})",
+ "syz_test$length8(&(0x7f000001f000)={0x38, {0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}, [{0xff, 0x1, 0x10, [0xff, 0xff, 0xff]}], 0x10, 0x1, [0xff, 0xff]})",
},
{
"syz_test$length9(&(0x7f000001f000)={&(0x7f0000000000/0x5000)=nil, (0x0000)})",
@@ -118,6 +118,10 @@ func TestAssignSize(t *testing.T) {
"syz_test$length19(&(0x7f0000000000)={{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0xff}, 0xff, 0xff, 0xff})",
"syz_test$length19(&(0x7f0000000000)={{0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x42, 0x14}, 0x14, 0x14, 0x5})",
},
+ {
+ "syz_test$length20(&(0x7f0000000000)={{{0xff, 0xff, 0xff, 0xff}, 0xff, 0xff, 0xff}, 0xff, 0xff})",
+ "syz_test$length20(&(0x7f0000000000)={{{0x4, 0x4, 0x7, 0x9}, 0x7, 0x7, 0x9}, 0x9, 0x9})",
+ },
}
for i, test := range tests {
diff --git a/prog/validation.go b/prog/validation.go
index 5eea42e65..f03ec10b8 100644
--- a/prog/validation.go
+++ b/prog/validation.go
@@ -59,6 +59,9 @@ func (c *Call) validate(ctx *validCtx) error {
if arg.Type.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.FieldName() != typ.FieldName() {
+ return fmt.Errorf("syscall %v: field name mismatch: %v vs %v", c.Meta.Name, arg.Type.FieldName(), typ.FieldName())
+ }
if arg.Type.Dir() == sys.DirOut {
if (arg.Val != 0 && arg.Val != arg.Type.Default()) || arg.AddrPage != 0 || arg.AddrOffset != 0 {
// We generate output len arguments, which makes sense