diff options
| author | Andrey Konovalov <andreyknvl@google.com> | 2017-07-11 16:49:08 +0200 |
|---|---|---|
| committer | Andrey Konovalov <andreyknvl@google.com> | 2017-07-17 14:34:09 +0200 |
| commit | cfc46d9d0bea72865ba75e0e4063a1a558262df8 (patch) | |
| tree | 80455a77ab10d09154bb1ae66a12de002b7cd030 /prog/clone.go | |
| parent | 8d1e7095528712971312a83e067cdd803aaccc47 (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.go | 79 |
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 |
