mirror of
https://github.com/reactos/syzkaller.git
synced 2024-11-23 19:39:40 +00:00
cfc46d9d0b
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.
84 lines
1.7 KiB
Go
84 lines
1.7 KiB
Go
// 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)
|
|
for _, c := range p.Calls {
|
|
c1 := new(Call)
|
|
c1.Meta = c.Meta
|
|
c1.Ret = clone(c.Ret, newargs)
|
|
for _, arg := range c.Args {
|
|
c1.Args = append(c1.Args, clone(arg, newargs))
|
|
}
|
|
p1.Calls = append(p1.Calls, c1)
|
|
}
|
|
if debug {
|
|
if err := p1.validate(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
return p1
|
|
}
|
|
|
|
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 *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))
|
|
}
|
|
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")
|
|
}
|
|
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 used, ok := arg1.(ArgUsed); ok {
|
|
*used.Used() = nil // filled when we clone the referent
|
|
newargs[arg] = arg1
|
|
}
|
|
return arg1
|
|
}
|