github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/signature-fuzzer/internal/fuzz-generator/parm.go (about)

     1  // Copyright 2021 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package generator
     6  
     7  import (
     8  	"bytes"
     9  	"fmt"
    10  	"os"
    11  	"sort"
    12  )
    13  
    14  // parm is an interface describing an abstract parameter var or return
    15  // var; there will be concrete types of various sorts that implement
    16  // this interface.
    17  type parm interface {
    18  
    19  	// Declare emits text containing a declaration of this param
    20  	// or return var into the specified buffer. Prefix is a tag to
    21  	// prepend before the declaration (for example a variable
    22  	// name) followed by a space; suffix is an arbitrary string to
    23  	// tack onto the end of the param's type text. Here 'caller'
    24  	// is set to true if we're emitting the caller part of a test
    25  	// pair as opposed to the checker.
    26  	Declare(b *bytes.Buffer, prefix string, suffix string, caller bool)
    27  
    28  	// GenElemRef returns a pair [X,Y] corresponding to a
    29  	// component piece of some composite parm, where X is a string
    30  	// forming the reference (ex: ".field" if we're picking out a
    31  	// struct field) and Y is a parm object corresponding to the
    32  	// type of the element.
    33  	GenElemRef(elidx int, path string) (string, parm)
    34  
    35  	// GenValue constructs a new concrete random value appropriate
    36  	// for the type in question and returns it, along with a
    37  	// sequence number indicating how many random decisions we had
    38  	// to make. Here "s" is the current generator state, "f" is
    39  	// the current function we're emitting, value is a sequence
    40  	// number indicating how many random decisions have been made
    41  	// up until this point, and 'caller' is set to true if we're
    42  	// emitting the caller part of a test pair as opposed to the
    43  	// checker.  Return value is a pair [V,I] where V is the text
    44  	// if the value, and I is a new sequence number reflecting any
    45  	// additional random choices we had to make.  For example, if
    46  	// the parm is something like "type Foo struct { f1 int32; f2
    47  	// float64 }" then we might expect GenValue to emit something
    48  	// like "Foo{int32(-9), float64(123.123)}".
    49  	GenValue(s *genstate, f *funcdef, value int, caller bool) (string, int)
    50  
    51  	// IsControl returns true if this specific param has been marked
    52  	// as the single param that controls recursion for a recursive
    53  	// checker function. The test code doesn't check this param for a specific
    54  	// value, but instead returns early if it has value 0 or decrements it
    55  	// on a recursive call.
    56  	IsControl() bool
    57  
    58  	// NumElements returns the total number of discrete elements contained
    59  	// in this parm. For non-composite types, this will always be 1.
    60  	NumElements() int
    61  
    62  	// String returns a descriptive string for this parm.
    63  	String() string
    64  
    65  	// TypeName returns the non-qualified type name for this parm.
    66  	TypeName() string
    67  
    68  	// QualName returns a package-qualified type name for this parm.
    69  	QualName() string
    70  
    71  	// HasPointer returns true if this parm is of pointer type, or
    72  	// if it is a composite that has a pointer element somewhere inside.
    73  	// Strings and slices return true for this hook.
    74  	HasPointer() bool
    75  
    76  	// IsBlank() returns true if the name of this parm is "_" (that is,
    77  	// if we randomly chose to make it a blank). SetBlank() is used
    78  	// to set the 'blank' property for this parm.
    79  	IsBlank() bool
    80  	SetBlank(v bool)
    81  
    82  	// AddrTaken() return a token indicating whether this parm should
    83  	// be address taken or not, the nature of the address-taken-ness (see
    84  	// below at the def of addrTakenHow). SetAddrTaken is used to set
    85  	// the address taken property of the parm.
    86  	AddrTaken() addrTakenHow
    87  	SetAddrTaken(val addrTakenHow)
    88  
    89  	// IsGenVal() returns true if the values of this type should
    90  	// be obtained by calling a helper func, as opposed to
    91  	// emitting code inline (as one would for things like numeric
    92  	// types). SetIsGenVal is used to set the gen-val property of
    93  	// the parm.
    94  	IsGenVal() bool
    95  	SetIsGenVal(val bool)
    96  
    97  	// SkipCompare() returns true if we've randomly decided that
    98  	// we don't want to compare the value for this param or
    99  	// return.  SetSkipCompare is used to set the skip-compare
   100  	// property of the parm.
   101  	SkipCompare() skipCompare
   102  	SetSkipCompare(val skipCompare)
   103  }
   104  
   105  type addrTakenHow uint8
   106  
   107  const (
   108  	// Param not address taken.
   109  	notAddrTaken addrTakenHow = 0
   110  
   111  	// Param address is taken and used for simple reads/writes.
   112  	addrTakenSimple addrTakenHow = 1
   113  
   114  	// Param address is taken and passed to a well-behaved function.
   115  	addrTakenPassed addrTakenHow = 2
   116  
   117  	// Param address is taken and stored to a global var.
   118  	addrTakenHeap addrTakenHow = 3
   119  )
   120  
   121  func (a *addrTakenHow) AddrTaken() addrTakenHow {
   122  	return *a
   123  }
   124  
   125  func (a *addrTakenHow) SetAddrTaken(val addrTakenHow) {
   126  	*a = val
   127  }
   128  
   129  type isBlank bool
   130  
   131  func (b *isBlank) IsBlank() bool {
   132  	return bool(*b)
   133  }
   134  
   135  func (b *isBlank) SetBlank(val bool) {
   136  	*b = isBlank(val)
   137  }
   138  
   139  type isGenValFunc bool
   140  
   141  func (g *isGenValFunc) IsGenVal() bool {
   142  	return bool(*g)
   143  }
   144  
   145  func (g *isGenValFunc) SetIsGenVal(val bool) {
   146  	*g = isGenValFunc(val)
   147  }
   148  
   149  type skipCompare int
   150  
   151  const (
   152  	// Param not address taken.
   153  	SkipAll     = -1
   154  	SkipNone    = 0
   155  	SkipPayload = 1
   156  )
   157  
   158  func (s *skipCompare) SkipCompare() skipCompare {
   159  	return skipCompare(*s)
   160  }
   161  
   162  func (s *skipCompare) SetSkipCompare(val skipCompare) {
   163  	*s = skipCompare(val)
   164  }
   165  
   166  // containedParms takes an arbitrary param 'p' and returns a slice
   167  // with 'p' itself plus any component parms contained within 'p'.
   168  func containedParms(p parm) []parm {
   169  	visited := make(map[string]parm)
   170  	worklist := []parm{p}
   171  
   172  	addToWork := func(p parm) {
   173  		if p == nil {
   174  			panic("not expected")
   175  		}
   176  		if _, ok := visited[p.TypeName()]; !ok {
   177  			worklist = append(worklist, p)
   178  		}
   179  	}
   180  
   181  	for len(worklist) != 0 {
   182  		cp := worklist[0]
   183  		worklist = worklist[1:]
   184  		if _, ok := visited[cp.TypeName()]; ok {
   185  			continue
   186  		}
   187  		visited[cp.TypeName()] = cp
   188  		switch x := cp.(type) {
   189  		case *mapparm:
   190  			addToWork(x.keytype)
   191  			addToWork(x.valtype)
   192  		case *structparm:
   193  			for _, fld := range x.fields {
   194  				addToWork(fld)
   195  			}
   196  		case *arrayparm:
   197  			addToWork(x.eltype)
   198  		case *pointerparm:
   199  			addToWork(x.totype)
   200  		case *typedefparm:
   201  			addToWork(x.target)
   202  		}
   203  	}
   204  	rv := []parm{}
   205  	for _, v := range visited {
   206  		rv = append(rv, v)
   207  	}
   208  	sort.Slice(rv, func(i, j int) bool {
   209  		if rv[i].TypeName() == rv[j].TypeName() {
   210  			fmt.Fprintf(os.Stderr, "%d %d %+v %+v %s %s\n", i, j, rv[i], rv[i].String(), rv[j], rv[j].String())
   211  			panic("unexpected")
   212  		}
   213  		return rv[i].TypeName() < rv[j].TypeName()
   214  	})
   215  	return rv
   216  }