github.com/google/syzkaller@v0.0.0-20240517125934-c0f1611a36d6/prog/clone.go (about) 1 // Copyright 2017 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package prog 5 6 import ( 7 "fmt" 8 ) 9 10 func (p *Prog) Clone() *Prog { 11 return p.cloneWithMap(make(map[*ResultArg]*ResultArg)) 12 } 13 14 func (p *Prog) cloneWithMap(newargs map[*ResultArg]*ResultArg) *Prog { 15 if p.isUnsafe { 16 // We could clone it, but since we prohibit mutation 17 // of unsafe programs, it's unclear why we would clone it. 18 // Note: this also covers cloning of corpus programs 19 // during mutation, so if this is removed, we may need 20 // additional checks during mutation. 21 panic("cloning of unsafe programs is not supposed to be done") 22 } 23 p1 := &Prog{ 24 Target: p.Target, 25 Calls: cloneCalls(p.Calls, newargs), 26 } 27 p1.debugValidate() 28 return p1 29 } 30 31 func cloneCalls(origCalls []*Call, newargs map[*ResultArg]*ResultArg) []*Call { 32 calls := make([]*Call, len(origCalls)) 33 for ci, c := range origCalls { 34 calls[ci] = cloneCall(c, newargs) 35 } 36 return calls 37 } 38 39 func cloneCall(c *Call, newargs map[*ResultArg]*ResultArg) *Call { 40 c1 := new(Call) 41 c1.Meta = c.Meta 42 if c.Ret != nil { 43 c1.Ret = clone(c.Ret, newargs).(*ResultArg) 44 } 45 c1.Args = make([]Arg, len(c.Args)) 46 for ai, arg := range c.Args { 47 c1.Args[ai] = clone(arg, newargs) 48 } 49 c1.Props = c.Props 50 return c1 51 } 52 53 func CloneArg(arg Arg) Arg { 54 return clone(arg, nil) 55 } 56 57 func clone(arg Arg, newargs map[*ResultArg]*ResultArg) Arg { 58 var arg1 Arg 59 switch a := arg.(type) { 60 case *ConstArg: 61 a1 := new(ConstArg) 62 *a1 = *a 63 arg1 = a1 64 case *PointerArg: 65 a1 := new(PointerArg) 66 *a1 = *a 67 arg1 = a1 68 if a.Res != nil { 69 a1.Res = clone(a.Res, newargs) 70 } 71 case *DataArg: 72 a1 := new(DataArg) 73 *a1 = *a 74 a1.data = append([]byte{}, a.data...) 75 arg1 = a1 76 case *GroupArg: 77 a1 := new(GroupArg) 78 *a1 = *a 79 arg1 = a1 80 a1.Inner = make([]Arg, len(a.Inner)) 81 for i, arg2 := range a.Inner { 82 a1.Inner[i] = clone(arg2, newargs) 83 } 84 case *UnionArg: 85 a1 := new(UnionArg) 86 *a1 = *a 87 arg1 = a1 88 a1.Option = clone(a.Option, newargs) 89 case *ResultArg: 90 a1 := new(ResultArg) 91 *a1 = *a 92 arg1 = a1 93 if a1.Res != nil { 94 r := a1.Res 95 if newargs != nil { 96 r = newargs[a1.Res] 97 a1.Res = r 98 } 99 if r.uses == nil { 100 r.uses = make(map[*ResultArg]bool) 101 } 102 r.uses[a1] = true 103 } 104 a1.uses = nil // filled when we clone the referent 105 if newargs != nil { 106 newargs[a] = a1 107 } 108 default: 109 panic(fmt.Sprintf("bad arg kind: %#v", arg)) 110 } 111 return arg1 112 }