syzkaller/prog/clone.go
Dmitry Vyukov 52a33fd516 prog: remove default target and all global state
Now each prog function accepts the desired target explicitly.
No global, implicit state involved.
This is much cleaner and allows cross-OS/arch testing, etc.
2017-09-15 16:02:37 +02:00

93 lines
1.9 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, _ := p.cloneImpl(false)
return p1
}
func (p *Prog) cloneImpl(full bool) (*Prog, map[Arg]Arg) {
p1 := &Prog{
Target: p.Target,
}
newargs := make(map[Arg]Arg)
for _, c := range p.Calls {
c1 := new(Call)
c1.Meta = c.Meta
c1.Ret = clone(c.Ret, newargs, full)
for _, arg := range c.Args {
c1.Args = append(c1.Args, clone(arg, newargs, full))
}
p1.Calls = append(p1.Calls, c1)
}
if debug {
if err := p1.validate(); err != nil {
panic(err)
}
}
return p1, newargs
}
func clone(arg Arg, newargs map[Arg]Arg, full bool) 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, full)
}
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, full))
}
case *UnionArg:
a1 := new(UnionArg)
*a1 = *a
arg1 = a1
a1.Option = clone(a.Option, newargs, full)
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
} else if full {
newargs[arg] = arg1
}
return arg1
}