github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/signature-fuzzer/fuzz-driver/driver.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 // Stand-alone driver for emitting function-signature test code. This 6 // program is mainly just a wrapper around the code that lives in the 7 // fuzz-generator package; it is useful for generating a specific bad 8 // code scenario for a given seed, or for doing development on the 9 // fuzzer, but for doing actual fuzz testing, better to use 10 // fuzz-runner. 11 12 package main 13 14 import ( 15 "flag" 16 "fmt" 17 "log" 18 "math/rand" 19 "os" 20 "time" 21 22 generator "golang.org/x/tools/cmd/signature-fuzzer/internal/fuzz-generator" 23 ) 24 25 // Basic options 26 var numfcnflag = flag.Int("numfcns", 10, "Number of test func pairs to emit in each package") 27 var numpkgflag = flag.Int("numpkgs", 1, "Number of test packages to emit") 28 var seedflag = flag.Int64("seed", -1, "Random seed") 29 var tagflag = flag.String("tag", "gen", "Prefix name of go files/pkgs to generate") 30 var outdirflag = flag.String("outdir", "", "Output directory for generated files") 31 var pkgpathflag = flag.String("pkgpath", "gen", "Base package path for generated files") 32 33 // Options used for test case minimization. 34 var fcnmaskflag = flag.String("fcnmask", "", "Mask containing list of fcn numbers to emit") 35 var pkmaskflag = flag.String("pkgmask", "", "Mask containing list of pkg numbers to emit") 36 37 // Options used to control which features are used in the generated code. 38 var reflectflag = flag.Bool("reflect", true, "Include testing of reflect.Call.") 39 var deferflag = flag.Bool("defer", true, "Include testing of defer stmts.") 40 var recurflag = flag.Bool("recur", true, "Include testing of recursive calls.") 41 var takeaddrflag = flag.Bool("takeaddr", true, "Include functions that take the address of their parameters and results.") 42 var methodflag = flag.Bool("method", true, "Include testing of method calls.") 43 var inlimitflag = flag.Int("inmax", -1, "Max number of input params.") 44 var outlimitflag = flag.Int("outmax", -1, "Max number of input params.") 45 var pragmaflag = flag.String("pragma", "", "Tag generated test routines with pragma //go:<value>.") 46 var maxfailflag = flag.Int("maxfail", 10, "Maximum runtime failures before test self-terminates") 47 var stackforceflag = flag.Bool("forcestackgrowth", true, "Use hooks to force stack growth.") 48 49 // Debugging options 50 var verbflag = flag.Int("v", 0, "Verbose trace output level") 51 52 // Debugging/testing options. These tell the generator to emit "bad" code so as to 53 // test the logic for detecting errors and/or minimization (in the fuzz runner). 54 var emitbadflag = flag.Int("emitbad", 0, "[Testing only] force generator to emit 'bad' code.") 55 var selbadpkgflag = flag.Int("badpkgidx", 0, "[Testing only] select index of bad package (used with -emitbad)") 56 var selbadfcnflag = flag.Int("badfcnidx", 0, "[Testing only] select index of bad function (used with -emitbad)") 57 58 // Misc options 59 var goimpflag = flag.Bool("goimports", false, "Run 'goimports' on generated code.") 60 var randctlflag = flag.Int("randctl", generator.RandCtlChecks|generator.RandCtlPanic, "Wraprand control flag") 61 62 func verb(vlevel int, s string, a ...interface{}) { 63 if *verbflag >= vlevel { 64 fmt.Printf(s, a...) 65 fmt.Printf("\n") 66 } 67 } 68 69 func usage(msg string) { 70 if len(msg) > 0 { 71 fmt.Fprintf(os.Stderr, "error: %s\n", msg) 72 } 73 fmt.Fprintf(os.Stderr, "usage: fuzz-driver [flags]\n\n") 74 flag.PrintDefaults() 75 fmt.Fprintf(os.Stderr, "Example:\n\n") 76 fmt.Fprintf(os.Stderr, " fuzz-driver -numpkgs=23 -numfcns=19 -seed 10101 -outdir gendir\n\n") 77 fmt.Fprintf(os.Stderr, " \tgenerates a Go program with 437 test cases (23 packages, each \n") 78 fmt.Fprintf(os.Stderr, " \twith 19 functions, for a total of 437 funcs total) into a set of\n") 79 fmt.Fprintf(os.Stderr, " \tsub-directories in 'gendir', using random see 10101\n") 80 81 os.Exit(2) 82 } 83 84 func setupTunables() { 85 tunables := generator.DefaultTunables() 86 if !*reflectflag { 87 tunables.DisableReflectionCalls() 88 } 89 if !*deferflag { 90 tunables.DisableDefer() 91 } 92 if !*recurflag { 93 tunables.DisableRecursiveCalls() 94 } 95 if !*takeaddrflag { 96 tunables.DisableTakeAddr() 97 } 98 if !*methodflag { 99 tunables.DisableMethodCalls() 100 } 101 if *inlimitflag != -1 { 102 tunables.LimitInputs(*inlimitflag) 103 } 104 if *outlimitflag != -1 { 105 tunables.LimitOutputs(*outlimitflag) 106 } 107 generator.SetTunables(tunables) 108 } 109 110 func main() { 111 log.SetFlags(0) 112 log.SetPrefix("fuzz-driver: ") 113 flag.Parse() 114 generator.Verbctl = *verbflag 115 if *outdirflag == "" { 116 usage("select an output directory with -o flag") 117 } 118 verb(1, "in main verblevel=%d", *verbflag) 119 if *seedflag == -1 { 120 // user has not selected a specific seed -- pick one. 121 now := time.Now() 122 *seedflag = now.UnixNano() % 123456789 123 verb(0, "selected seed: %d", *seedflag) 124 } 125 rand.Seed(*seedflag) 126 if flag.NArg() != 0 { 127 usage("unknown extra arguments") 128 } 129 verb(1, "tag is %s", *tagflag) 130 131 fcnmask, err := generator.ParseMaskString(*fcnmaskflag, "fcn") 132 if err != nil { 133 usage(fmt.Sprintf("mangled fcn mask arg: %v", err)) 134 } 135 pkmask, err := generator.ParseMaskString(*pkmaskflag, "pkg") 136 if err != nil { 137 usage(fmt.Sprintf("mangled pkg mask arg: %v", err)) 138 } 139 verb(2, "pkg mask is %v", pkmask) 140 verb(2, "fn mask is %v", fcnmask) 141 142 verb(1, "starting generation") 143 setupTunables() 144 config := generator.GenConfig{ 145 PkgPath: *pkgpathflag, 146 Tag: *tagflag, 147 OutDir: *outdirflag, 148 NumTestPackages: *numpkgflag, 149 NumTestFunctions: *numfcnflag, 150 Seed: *seedflag, 151 Pragma: *pragmaflag, 152 FcnMask: fcnmask, 153 PkgMask: pkmask, 154 MaxFail: *maxfailflag, 155 ForceStackGrowth: *stackforceflag, 156 RandCtl: *randctlflag, 157 RunGoImports: *goimpflag, 158 EmitBad: *emitbadflag, 159 BadPackageIdx: *selbadpkgflag, 160 BadFuncIdx: *selbadfcnflag, 161 } 162 errs := generator.Generate(config) 163 if errs != 0 { 164 log.Fatal("errors during generation") 165 } 166 verb(1, "... files written to directory %s", *outdirflag) 167 verb(1, "leaving main") 168 }