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  }