aboutsummaryrefslogtreecommitdiffstats
path: root/prog/clone.go
diff options
context:
space:
mode:
authorAndrey Konovalov <andreyknvl@google.com>2017-07-11 16:49:08 +0200
committerAndrey Konovalov <andreyknvl@google.com>2017-07-17 14:34:09 +0200
commitcfc46d9d0bea72865ba75e0e4063a1a558262df8 (patch)
tree80455a77ab10d09154bb1ae66a12de002b7cd030 /prog/clone.go
parent8d1e7095528712971312a83e067cdd803aaccc47 (diff)
prog: split Arg into smaller structs
Right now Arg is a huge struct (160 bytes), which has many different fields used for different arg kinds. Since most of the args we see in a typical corpus are ArgConst, this results in a significant memory overuse. This change: - makes Arg an interface instead of a struct - adds a SomethingArg struct for each arg kind we have - converts all *Arg pointers into just Arg, since interface variable by itself contains a pointer to the actual data - removes ArgPageSize, now ConstArg is used instead - consolidates correspondence between arg kinds and types, see comments before each SomethingArg struct definition - now LenType args that denote the length of VmaType args are serialized as "0x1000" instead of "(0x1000)"; to preserve backwards compatibility syzkaller is able to parse the old format for now - multiple small changes all over to make the above work After this change syzkaller uses twice less memory after deserializing a typical corpus.
Diffstat (limited to 'prog/clone.go')
-rw-r--r--prog/clone.go79
1 files changed, 54 insertions, 25 deletions
diff --git a/prog/clone.go b/prog/clone.go
index c085b765f..fcd651845 100644
--- a/prog/clone.go
+++ b/prog/clone.go
@@ -1,17 +1,17 @@
-// Copyright 2015 syzkaller project authors. All rights reserved.
+// Copyright 2017 syzkaller project authors. All rights reserved.
// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
package prog
func (p *Prog) Clone() *Prog {
p1 := new(Prog)
- newargs := make(map[*Arg]*Arg)
+ newargs := make(map[Arg]Arg)
for _, c := range p.Calls {
c1 := new(Call)
c1.Meta = c.Meta
- c1.Ret = c.Ret.clone(c1, newargs)
+ c1.Ret = clone(c.Ret, newargs)
for _, arg := range c.Args {
- c1.Args = append(c1.Args, arg.clone(c1, newargs))
+ c1.Args = append(c1.Args, clone(arg, newargs))
}
p1.Calls = append(p1.Calls, c1)
}
@@ -23,31 +23,60 @@ func (p *Prog) Clone() *Prog {
return p1
}
-func (arg *Arg) clone(c *Call, newargs map[*Arg]*Arg) *Arg {
- arg1 := new(Arg)
- *arg1 = *arg
- arg1.Data = append([]byte{}, arg.Data...)
- switch arg.Kind {
- case ArgPointer:
- if arg.Res != nil {
- arg1.Res = arg.Res.clone(c, newargs)
+func clone(arg Arg, newargs map[Arg]Arg) Arg {
+ var arg1 Arg
+ switch a := arg.(type) {
+ case *ConstArg:
+ a1 := new(ConstArg)
+ *a1 = *a
+ arg1 = a1
+ case *PointerArg:
+ a1 := new(PointerArg)
+ *a1 = *a
+ arg1 = a1
+ if a.Res != nil {
+ a1.Res = clone(a.Res, newargs)
}
- case ArgUnion:
- arg1.Option = arg.Option.clone(c, newargs)
- case ArgResult:
- r := newargs[arg.Res]
- arg1.Res = r
- if r.Uses == nil {
- r.Uses = make(map[*Arg]bool)
+ case *DataArg:
+ a1 := new(DataArg)
+ *a1 = *a
+ a1.Data = append([]byte{}, a.Data...)
+ arg1 = a1
+ case *GroupArg:
+ a1 := new(GroupArg)
+ *a1 = *a
+ arg1 = a1
+ a1.Inner = nil
+ for _, arg2 := range a.Inner {
+ a1.Inner = append(a1.Inner, clone(arg2, newargs))
}
- r.Uses[arg1] = true
+ case *UnionArg:
+ a1 := new(UnionArg)
+ *a1 = *a
+ arg1 = a1
+ a1.Option = clone(a.Option, newargs)
+ case *ResultArg:
+ a1 := new(ResultArg)
+ *a1 = *a
+ arg1 = a1
+ case *ReturnArg:
+ a1 := new(ReturnArg)
+ *a1 = *a
+ arg1 = a1
+ default:
+ panic("bad arg kind")
}
- arg1.Inner = nil
- for _, arg2 := range arg.Inner {
- arg1.Inner = append(arg1.Inner, arg2.clone(c, newargs))
+ if user, ok := arg1.(ArgUser); ok && *user.Uses() != nil {
+ r := newargs[*user.Uses()]
+ *user.Uses() = r
+ used := r.(ArgUsed)
+ if *used.Used() == nil {
+ *used.Used() = make(map[Arg]bool)
+ }
+ (*used.Used())[arg1] = true
}
- if len(arg1.Uses) != 0 {
- arg1.Uses = nil // filled when we clone the referent
+ if used, ok := arg1.(ArgUsed); ok {
+ *used.Used() = nil // filled when we clone the referent
newargs[arg] = arg1
}
return arg1