github.com/cockroachdb/tools@v0.0.0-20230222021103-a6d27438930d/cmd/signature-fuzzer/internal/fuzz-generator/generator.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 // This package generates source code for a stand-alone Go program 6 // useful for function signature fuzzing. The generated program is a 7 // series of function pairs, a "Caller" function and a "Checker" 8 // function. The signature of the Checker function is generated 9 // randomly (random number of parameters and returns, each with 10 // randomly chosen types). The "Caller" func contains invocations of 11 // the "Checker" function, each passing randomly chosen values to the 12 // params of the "Checker", then the caller verifies that expected 13 // values are returned correctly. The "Checker" function in turn has 14 // code to verify that the expected values arrive correctly, and so 15 // on. 16 // 17 // The main exported items of interest for this package are: 18 // 19 // - the Generate function, which takes a GenConfig object and emits 20 // code according to the config's specification 21 // 22 // - the GenConfig struct, which is basically a large collection of 23 // knobs/switches to control the mechanics of how/where code is 24 // generated 25 // 26 // - the TunableParams struct, which controls the nature of the 27 // generated code (for example, the maximum number of function 28 // parameters, etc), and the SetTunables func which tells the 29 // package what tunable parameters to use. 30 31 // Notes for posterity: 32 // - many parts of this package would have been better off being written 33 // using text/template instead of generating code directly; perhaps 34 // at some point it could be converted over (big job). 35 // - for the various 'fractions' fields in the TunableParams struct, 36 // it would be good to have a named type of some sort, with methods 37 // for managing things like checking to make sure values sum to 100. 38 39 package generator 40 41 import ( 42 "bytes" 43 "crypto/sha1" 44 "errors" 45 "fmt" 46 "html/template" 47 "log" 48 "os" 49 "os/exec" 50 "path/filepath" 51 "strconv" 52 "strings" 53 ) 54 55 // GenConfig contains configuration parameters relating to the 56 // mechanics of the code generation, e.g. how many packages/functions 57 // to emit, path to a directory into which we place the generated 58 // code, prefixes/packagenames for the generate code, and so on. 59 type GenConfig struct { 60 // Tag is a string prefix prepended to functions within 61 // the generated code. 62 Tag string 63 64 // Output directory in to which we'll emit generated code. 65 // This will be created if it does not exist. 66 OutDir string 67 68 // Packagepath prefix given to the generated code. 69 PkgPath string 70 71 // Number of test packages created within the generated corpus. 72 // Each test package is essentially an independent collection 73 // generated code; the point of having multiple packages is to 74 // be able to get faster builds (more parallelism), and to avoid 75 // the compile time issues that crop up with 'giant' packages. 76 NumTestPackages int 77 78 // Number of test function pairs within each generated test package. 79 // Each pair consists of a "caller" function and "callee" function. 80 NumTestFunctions int 81 82 // Seed for random number generator. 83 Seed int64 84 85 // Pragma is a "// go:..." compiler directive to apply to the 86 // callee function as part of a generated function pair. 87 Pragma string 88 89 // Function and package mask used for minimization purposes. 90 // If a given mask is non-nil, then the generator will only 91 // emit code for a given func or package if its index is 92 // present in the mask map. 93 FcnMask map[int]int 94 PkgMask map[int]int 95 96 // Maximum number of failures to encounter before bailing out. 97 MaxFail int 98 99 // forcestackgrowth if set tells the generator to insert 100 // calls to runtime.gcTestMoveStackOnNextCall at various points 101 // in the generated code. 102 ForceStackGrowth bool 103 104 // Random number generator control flag (debugging) 105 RandCtl int 106 107 // Tells the generator to run "goimports" on the emitted code. 108 RunGoImports bool 109 110 // Debugging/testing hook. If set to 1, emit code that will cause the 111 // build to fail; if set to 2, emit code that will cause a test to fail. 112 EmitBad int 113 114 // If EmitBad above is set, then these can be used to select the ID of 115 // a specific bad func/package. 116 BadPackageIdx int 117 BadFuncIdx int 118 } 119 120 const CallerName = "Caller" 121 const CheckerName = "Checker" 122 123 // TunableParams contains configuration parameters that control the 124 // flavor of code generated for a given test function. This includes 125 // things like the number of params/returns, the percentages of types 126 // (int, struct, etc) of the params/returns, and so on. 127 type TunableParams struct { 128 // between 0 and N params 129 nParmRange uint8 130 131 // between 0 and N returns 132 nReturnRange uint8 133 134 // structs have between 0 and N members 135 nStructFields uint8 136 137 // arrays/slices have between 0 and N elements 138 nArrayElements uint8 139 140 // fraction of slices vs arrays. This is a value between 0 and 100 (0 meaning 141 // no slices [only arrays] and 100 meaning all slices, no arrays). 142 sliceFraction uint8 143 144 // Controls how often "int" vars wind up as 8/16/32/64, should 145 // add up to 100. Ex: 100 0 0 0 means all ints are 8 bit, 25 146 // 25 25 25 means equal likelihood of all types. 147 intBitRanges [4]uint8 148 149 // Similar to the above but for 32/64 float types 150 floatBitRanges [2]uint8 151 152 // Similar to the above but for unsigned, signed ints. 153 unsignedRanges [2]uint8 154 155 // Percentage of params, struct fields that should be "_". Ranges 156 // from 0 to 100. 157 blankPerc uint8 158 159 // How deeply structs are allowed to be nested (ranges from 0 to N). 160 structDepth uint8 161 162 // Fraction of param and return types assigned to each of: 163 // struct/array/map/pointer/int/float/complex/byte/string at the 164 // top level. If nesting precludes using a struct, other types 165 // are chosen from instead according to same proportions. The sum 166 // of typeFractions values should add up to 100. 167 typeFractions [9]uint8 168 169 // Percentage of the time we'll emit recursive calls, from 0 to 100. 170 recurPerc uint8 171 172 // Percentage of time that we turn the test function into a method, 173 // and if it is a method, fraction of time that we use a pointer 174 // method call vs value method call. Each range from 0 to 100. 175 methodPerc uint8 176 pointerMethodCallPerc uint8 177 178 // If true, test reflect.Call path as well. 179 doReflectCall bool 180 181 // If true, then randomly take addresses of params/returns. 182 takeAddress bool 183 184 // Fraction of the time that any params/returns are address taken. 185 // Ranges from 0 to 100. 186 takenFraction uint8 187 188 // For a given address-taken param or return, controls the 189 // manner in which the indirect read or write takes 190 // place. This is a set of percentages for 191 // not/simple/passed/heap, where "not" means not address 192 // taken, "simple" means a simple read or write, "passed" 193 // means that the address is passed to a well-behaved 194 // function, and "heap" means that the address is assigned to 195 // a global. Values in addrFractions should add up to 100. 196 addrFractions [4]uint8 197 198 // If true, then perform testing of go/defer statements. 199 doDefer bool 200 201 // fraction of test functions for which we emit a defer. Ranges from 0 to 100. 202 deferFraction uint8 203 204 // If true, randomly pick between emitting a value by literal 205 // (e.g. "int(1)" vs emitting a call to a function that 206 // will produce the same value (e.g. "myHelperEmitsInt1()"). 207 doFuncCallValues bool 208 209 // Fraction of the time that we emit a function call to create 210 // a param value vs emitting a literal. Ranges from 0 to 100. 211 funcCallValFraction uint8 212 213 // If true, randomly decide to not check selected components of 214 // a composite value (e.g. for a struct, check field F1 but not F2). 215 // The intent is to generate partially live values. 216 doSkipCompare bool 217 218 // Fraction of the time that we decided to skip sub-components of 219 // composite values. Ranges from 0 to 100. 220 skipCompareFraction uint8 221 } 222 223 // SetTunables accepts a TunableParams object, checks to make sure 224 // that the settings in it are sane/logical, and applies the 225 // parameters for any subsequent calls to the Generate function. This 226 // function will issue a fatal error if any of the tunable params are 227 // incorrect/insane (for example, a 'percentage' value outside the 228 // range of 0-100). 229 func SetTunables(t TunableParams) { 230 checkTunables(t) 231 tunables = t 232 } 233 234 var defaultTypeFractions = [9]uint8{ 235 10, // struct 236 10, // array 237 10, // map 238 15, // pointer 239 20, // numeric 240 15, // float 241 5, // complex 242 5, // byte 243 10, // string 244 } 245 246 const ( 247 // Param not address taken. 248 StructTfIdx = iota 249 ArrayTfIdx 250 MapTfIdx 251 PointerTfIdx 252 NumericTfIdx 253 FloatTfIdx 254 ComplexTfIdx 255 ByteTfIdx 256 StringTfIdx 257 ) 258 259 var tunables = TunableParams{ 260 nParmRange: 15, 261 nReturnRange: 7, 262 nStructFields: 7, 263 nArrayElements: 5, 264 sliceFraction: 50, 265 intBitRanges: [4]uint8{30, 20, 20, 30}, 266 floatBitRanges: [2]uint8{50, 50}, 267 unsignedRanges: [2]uint8{50, 50}, 268 blankPerc: 15, 269 structDepth: 3, 270 typeFractions: defaultTypeFractions, 271 recurPerc: 20, 272 methodPerc: 10, 273 pointerMethodCallPerc: 50, 274 doReflectCall: true, 275 doDefer: true, 276 takeAddress: true, 277 doFuncCallValues: true, 278 takenFraction: 20, 279 deferFraction: 30, 280 funcCallValFraction: 5, 281 doSkipCompare: true, 282 skipCompareFraction: 10, 283 addrFractions: [4]uint8{50, 25, 15, 10}, 284 } 285 286 func DefaultTunables() TunableParams { 287 return tunables 288 } 289 290 func checkTunables(t TunableParams) { 291 var s int = 0 292 293 for _, v := range t.intBitRanges { 294 s += int(v) 295 } 296 if s != 100 { 297 log.Fatal(errors.New("intBitRanges tunable does not sum to 100")) 298 } 299 300 s = 0 301 for _, v := range t.unsignedRanges { 302 s += int(v) 303 } 304 if s != 100 { 305 log.Fatal(errors.New("unsignedRanges tunable does not sum to 100")) 306 } 307 308 if t.blankPerc > 100 { 309 log.Fatal(errors.New("blankPerc bad value, over 100")) 310 } 311 if t.recurPerc > 100 { 312 log.Fatal(errors.New("recurPerc bad value, over 100")) 313 } 314 if t.methodPerc > 100 { 315 log.Fatal(errors.New("methodPerc bad value, over 100")) 316 } 317 if t.pointerMethodCallPerc > 100 { 318 log.Fatal(errors.New("pointerMethodCallPerc bad value, over 100")) 319 } 320 321 s = 0 322 for _, v := range t.floatBitRanges { 323 s += int(v) 324 } 325 if s != 100 { 326 log.Fatal(errors.New("floatBitRanges tunable does not sum to 100")) 327 } 328 329 s = 0 330 for _, v := range t.typeFractions { 331 s += int(v) 332 } 333 if s != 100 { 334 panic(errors.New("typeFractions tunable does not sum to 100")) 335 } 336 337 s = 0 338 for _, v := range t.addrFractions { 339 s += int(v) 340 } 341 if s != 100 { 342 log.Fatal(errors.New("addrFractions tunable does not sum to 100")) 343 } 344 if t.takenFraction > 100 { 345 log.Fatal(errors.New("takenFraction not between 0 and 100")) 346 } 347 if t.deferFraction > 100 { 348 log.Fatal(errors.New("deferFraction not between 0 and 100")) 349 } 350 if t.sliceFraction > 100 { 351 log.Fatal(errors.New("sliceFraction not between 0 and 100")) 352 } 353 if t.skipCompareFraction > 100 { 354 log.Fatal(errors.New("skipCompareFraction not between 0 and 100")) 355 } 356 } 357 358 func (t *TunableParams) DisableReflectionCalls() { 359 t.doReflectCall = false 360 } 361 362 func (t *TunableParams) DisableRecursiveCalls() { 363 t.recurPerc = 0 364 } 365 366 func (t *TunableParams) DisableMethodCalls() { 367 t.methodPerc = 0 368 } 369 370 func (t *TunableParams) DisableTakeAddr() { 371 t.takeAddress = false 372 } 373 374 func (t *TunableParams) DisableDefer() { 375 t.doDefer = false 376 } 377 378 func (t *TunableParams) LimitInputs(n int) error { 379 if n > 100 { 380 return fmt.Errorf("value %d passed to LimitInputs is too large *(max 100)", n) 381 } 382 if n < 0 { 383 return fmt.Errorf("value %d passed to LimitInputs is invalid", n) 384 } 385 t.nParmRange = uint8(n) 386 return nil 387 } 388 389 func (t *TunableParams) LimitOutputs(n int) error { 390 if n > 100 { 391 return fmt.Errorf("value %d passed to LimitOutputs is too large *(max 100)", n) 392 } 393 if n < 0 { 394 return fmt.Errorf("value %d passed to LimitOutputs is invalid", n) 395 } 396 t.nReturnRange = uint8(n) 397 return nil 398 } 399 400 // ParseMaskString parses a string of the form K,J,...,M-N,Q-R,...,Z 401 // e.g. comma-separated integers or ranges of integers, returning the 402 // result in a form suitable for FcnMask or PkgMask fields in a 403 // Config. Here "tag" holds the mask flavor (fcn or pkg) and "arg" is 404 // the string argument to be parsed. 405 func ParseMaskString(arg string, tag string) (map[int]int, error) { 406 if arg == "" { 407 return nil, nil 408 } 409 verb(1, "%s mask is %s", tag, arg) 410 m := make(map[int]int) 411 ss := strings.Split(arg, ":") 412 for _, s := range ss { 413 if strings.Contains(s, "-") { 414 rng := strings.Split(s, "-") 415 if len(rng) != 2 { 416 return nil, fmt.Errorf("malformed range %s in %s mask arg", s, tag) 417 } 418 i, err := strconv.Atoi(rng[0]) 419 if err != nil { 420 return nil, fmt.Errorf("malformed range value %s in %s mask arg", rng[0], tag) 421 } 422 j, err2 := strconv.Atoi(rng[1]) 423 if err2 != nil { 424 return nil, fmt.Errorf("malformed range value %s in %s mask arg", rng[1], tag) 425 } 426 for k := i; k < j; k++ { 427 m[k] = 1 428 } 429 } else { 430 i, err := strconv.Atoi(s) 431 if err != nil { 432 return nil, fmt.Errorf("malformed value %s in %s mask arg", s, tag) 433 } 434 m[i] = 1 435 } 436 } 437 return m, nil 438 } 439 440 func writeCom(b *bytes.Buffer, i int) { 441 if i != 0 { 442 b.WriteString(", ") 443 } 444 } 445 446 var Verbctl int = 0 447 448 func verb(vlevel int, s string, a ...interface{}) { 449 if Verbctl >= vlevel { 450 fmt.Printf(s, a...) 451 fmt.Printf("\n") 452 } 453 } 454 455 type funcdef struct { 456 idx int 457 structdefs []structparm 458 arraydefs []arrayparm 459 typedefs []typedefparm 460 mapdefs []mapparm 461 mapkeytypes []parm 462 mapkeytmps []string 463 mapkeyts string 464 receiver parm 465 params []parm 466 returns []parm 467 values []int 468 dodefc uint8 469 dodefp []uint8 470 rstack int 471 recur bool 472 isMethod bool 473 } 474 475 type genstate struct { 476 GenConfig 477 ipref string 478 //tag string 479 //numtpk int 480 pkidx int 481 errs int 482 //pragma string 483 //sforce bool 484 //randctl int 485 tunables TunableParams 486 tstack []TunableParams 487 derefFuncs map[string]string 488 newDerefFuncs []funcdesc 489 assignFuncs map[string]string 490 newAssignFuncs []funcdesc 491 allocFuncs map[string]string 492 newAllocFuncs []funcdesc 493 genvalFuncs map[string]string 494 newGenvalFuncs []funcdesc 495 globVars map[string]string 496 newGlobVars []funcdesc 497 wr *wraprand 498 } 499 500 func (s *genstate) intFlavor() string { 501 which := uint8(s.wr.Intn(100)) 502 if which < s.tunables.unsignedRanges[0] { 503 return "uint" 504 } 505 return "int" 506 } 507 508 func (s *genstate) intBits() uint32 { 509 which := uint8(s.wr.Intn(100)) 510 var t uint8 = 0 511 var bits uint32 = 8 512 for _, v := range s.tunables.intBitRanges { 513 t += v 514 if which < t { 515 return bits 516 } 517 bits *= 2 518 } 519 return uint32(s.tunables.intBitRanges[3]) 520 } 521 522 func (s *genstate) floatBits() uint32 { 523 which := uint8(s.wr.Intn(100)) 524 if which < s.tunables.floatBitRanges[0] { 525 return uint32(32) 526 } 527 return uint32(64) 528 } 529 530 func (s *genstate) genAddrTaken() addrTakenHow { 531 which := uint8(s.wr.Intn(100)) 532 res := notAddrTaken 533 var t uint8 = 0 534 for _, v := range s.tunables.addrFractions { 535 t += v 536 if which < t { 537 return res 538 } 539 res++ 540 } 541 return notAddrTaken 542 } 543 544 func (s *genstate) pushTunables() { 545 s.tstack = append(s.tstack, s.tunables) 546 } 547 548 func (s *genstate) popTunables() { 549 if len(s.tstack) == 0 { 550 panic("untables stack underflow") 551 } 552 s.tunables = s.tstack[0] 553 s.tstack = s.tstack[1:] 554 } 555 556 // redistributeFraction accepts a value 'toIncorporate' and updates 557 // 'typeFraction' to add in the values from 'toIncorporate' equally to 558 // all slots not in 'avoid'. This is done by successively walking 559 // through 'typeFraction' adding 1 to each non-avoid slot, then 560 // repeating until we've added a total of 'toIncorporate' elements. 561 // See precludeSelectedTypes below for more info. 562 func (s *genstate) redistributeFraction(toIncorporate uint8, avoid []int) { 563 inavoid := func(j int) bool { 564 for _, k := range avoid { 565 if j == k { 566 return true 567 } 568 } 569 return false 570 } 571 572 doredis := func() { 573 for { 574 for i := range s.tunables.typeFractions { 575 if inavoid(i) { 576 continue 577 } 578 s.tunables.typeFractions[i]++ 579 toIncorporate-- 580 if toIncorporate == 0 { 581 return 582 } 583 } 584 } 585 } 586 doredis() 587 checkTunables(s.tunables) 588 } 589 590 // precludeSelectedTypes accepts a set of values (t, t2, ...) 591 // corresponding to slots in 'typeFractions', sums up the values from 592 // the slots, zeroes out the slots, and finally takes the values and 593 // redistributes them equally to the other slots. For example, 594 // suppose 'typeFractions' starts as [10, 10, 10, 15, 20, 15, 5, 5, 10], 595 // then we decide we want to eliminate or 'knock out' map types and 596 // pointer types (slots 2 and 3 in the array above) going forward. To 597 // restore the invariant that values in 'typeFractions' sum to 100, we 598 // take the values from slots 2 and 3 (a total of 25) and evenly 599 // distribute those values to the other slots in the array. 600 func (s *genstate) precludeSelectedTypes(t int, t2 ...int) { 601 avoid := []int{t} 602 avoid = append(avoid, t2...) 603 f := uint8(0) 604 for _, idx := range avoid { 605 f += s.tunables.typeFractions[idx] 606 s.tunables.typeFractions[idx] = 0 607 } 608 s.redistributeFraction(f, avoid) 609 } 610 611 func (s *genstate) GenMapKeyType(f *funcdef, depth int, pidx int) parm { 612 s.pushTunables() 613 defer s.popTunables() 614 // maps we can't allow at all; pointers might be possible but 615 // would be too much work to arrange. Avoid slices as well. 616 s.tunables.sliceFraction = 0 617 s.precludeSelectedTypes(MapTfIdx, PointerTfIdx) 618 return s.GenParm(f, depth+1, false, pidx) 619 } 620 621 func (s *genstate) GenParm(f *funcdef, depth int, mkctl bool, pidx int) parm { 622 623 // Enforcement for struct/array/map/pointer array nesting depth. 624 toodeep := depth >= int(s.tunables.structDepth) 625 if toodeep { 626 s.pushTunables() 627 defer s.popTunables() 628 s.precludeSelectedTypes(StructTfIdx, ArrayTfIdx, MapTfIdx, PointerTfIdx) 629 } 630 631 // Convert tf into a cumulative sum 632 tf := s.tunables.typeFractions 633 sum := uint8(0) 634 for i := 0; i < len(tf); i++ { 635 sum += tf[i] 636 tf[i] = sum 637 } 638 639 isblank := uint8(s.wr.Intn(100)) < s.tunables.blankPerc 640 addrTaken := notAddrTaken 641 if depth == 0 && tunables.takeAddress && !isblank { 642 addrTaken = s.genAddrTaken() 643 } 644 isGenValFunc := tunables.doFuncCallValues && 645 uint8(s.wr.Intn(100)) < s.tunables.funcCallValFraction 646 647 // Make adjusted selection (pick a bucket within tf) 648 which := uint8(s.wr.Intn(100)) 649 verb(3, "which=%d", which) 650 var retval parm 651 switch { 652 case which < tf[StructTfIdx]: 653 { 654 if toodeep { 655 panic("should not be here") 656 } 657 var sp structparm 658 ns := len(f.structdefs) 659 sp.sname = fmt.Sprintf("StructF%dS%d", f.idx, ns) 660 sp.qname = fmt.Sprintf("%s.StructF%dS%d", 661 s.checkerPkg(pidx), f.idx, ns) 662 f.structdefs = append(f.structdefs, sp) 663 tnf := int64(s.tunables.nStructFields) / int64(depth+1) 664 nf := int(s.wr.Intn(tnf)) 665 for fi := 0; fi < nf; fi++ { 666 fp := s.GenParm(f, depth+1, false, pidx) 667 skComp := tunables.doSkipCompare && 668 uint8(s.wr.Intn(100)) < s.tunables.skipCompareFraction 669 if skComp && checkableElements(fp) != 0 { 670 fp.SetSkipCompare(SkipAll) 671 } 672 sp.fields = append(sp.fields, fp) 673 } 674 f.structdefs[ns] = sp 675 retval = &sp 676 } 677 case which < tf[ArrayTfIdx]: 678 { 679 if toodeep { 680 panic("should not be here") 681 } 682 var ap arrayparm 683 ns := len(f.arraydefs) 684 nel := uint8(s.wr.Intn(int64(s.tunables.nArrayElements))) 685 issl := uint8(s.wr.Intn(100)) < s.tunables.sliceFraction 686 ap.aname = fmt.Sprintf("ArrayF%dS%dE%d", f.idx, ns, nel) 687 ap.qname = fmt.Sprintf("%s.ArrayF%dS%dE%d", s.checkerPkg(pidx), 688 f.idx, ns, nel) 689 f.arraydefs = append(f.arraydefs, ap) 690 ap.nelements = nel 691 ap.slice = issl 692 ap.eltype = s.GenParm(f, depth+1, false, pidx) 693 ap.eltype.SetBlank(false) 694 skComp := tunables.doSkipCompare && 695 uint8(s.wr.Intn(100)) < s.tunables.skipCompareFraction 696 if skComp && checkableElements(ap.eltype) != 0 { 697 if issl { 698 ap.SetSkipCompare(SkipPayload) 699 } 700 } 701 f.arraydefs[ns] = ap 702 retval = &ap 703 } 704 case which < tf[MapTfIdx]: 705 { 706 if toodeep { 707 panic("should not be here") 708 } 709 var mp mapparm 710 ns := len(f.mapdefs) 711 712 // append early, since calls below might also append 713 f.mapdefs = append(f.mapdefs, mp) 714 f.mapkeytmps = append(f.mapkeytmps, "") 715 f.mapkeytypes = append(f.mapkeytypes, mp.keytype) 716 mp.aname = fmt.Sprintf("MapF%dM%d", f.idx, ns) 717 if f.mapkeyts == "" { 718 f.mapkeyts = fmt.Sprintf("MapKeysF%d", f.idx) 719 } 720 mp.qname = fmt.Sprintf("%s.MapF%dM%d", s.checkerPkg(pidx), 721 f.idx, ns) 722 mkt := fmt.Sprintf("Mk%dt%d", f.idx, ns) 723 mp.keytmp = mkt 724 mk := s.GenMapKeyType(f, depth+1, pidx) 725 mp.keytype = mk 726 mp.valtype = s.GenParm(f, depth+1, false, pidx) 727 mp.valtype.SetBlank(false) 728 mp.keytype.SetBlank(false) 729 // now update the previously appended placeholders 730 f.mapdefs[ns] = mp 731 f.mapkeytypes[ns] = mk 732 f.mapkeytmps[ns] = mkt 733 retval = &mp 734 } 735 case which < tf[PointerTfIdx]: 736 { 737 if toodeep { 738 panic("should not be here") 739 } 740 pp := mkPointerParm(s.GenParm(f, depth+1, false, pidx)) 741 retval = &pp 742 } 743 case which < tf[NumericTfIdx]: 744 { 745 var ip numparm 746 ip.tag = s.intFlavor() 747 ip.widthInBits = s.intBits() 748 if mkctl { 749 ip.ctl = true 750 } 751 retval = &ip 752 } 753 case which < tf[FloatTfIdx]: 754 { 755 var fp numparm 756 fp.tag = "float" 757 fp.widthInBits = s.floatBits() 758 retval = &fp 759 } 760 case which < tf[ComplexTfIdx]: 761 { 762 var fp numparm 763 fp.tag = "complex" 764 fp.widthInBits = s.floatBits() * 2 765 retval = &fp 766 } 767 case which < tf[ByteTfIdx]: 768 { 769 var bp numparm 770 bp.tag = "byte" 771 bp.widthInBits = 8 772 retval = &bp 773 } 774 case which < tf[StringTfIdx]: 775 { 776 var sp stringparm 777 sp.tag = "string" 778 skComp := tunables.doSkipCompare && 779 uint8(s.wr.Intn(100)) < s.tunables.skipCompareFraction 780 if skComp { 781 sp.SetSkipCompare(SkipPayload) 782 } 783 retval = &sp 784 } 785 default: 786 { 787 // fallback 788 var ip numparm 789 ip.tag = "uint" 790 ip.widthInBits = 8 791 retval = &ip 792 } 793 } 794 if !mkctl { 795 retval.SetBlank(isblank) 796 } 797 retval.SetAddrTaken(addrTaken) 798 retval.SetIsGenVal(isGenValFunc) 799 return retval 800 } 801 802 func (s *genstate) GenReturn(f *funcdef, depth int, pidx int) parm { 803 return s.GenParm(f, depth, false, pidx) 804 } 805 806 // GenFunc cooks up the random signature (and other attributes) of a 807 // given checker function, returning a funcdef object that describes 808 // the new fcn. 809 func (s *genstate) GenFunc(fidx int, pidx int) *funcdef { 810 f := new(funcdef) 811 f.idx = fidx 812 numParams := int(s.wr.Intn(int64(1 + int(s.tunables.nParmRange)))) 813 numReturns := int(s.wr.Intn(int64(1 + int(s.tunables.nReturnRange)))) 814 f.recur = uint8(s.wr.Intn(100)) < s.tunables.recurPerc 815 f.isMethod = uint8(s.wr.Intn(100)) < s.tunables.methodPerc 816 genReceiverType := func() { 817 // Receiver type can't be pointer type. Temporarily update 818 // tunables to eliminate that possibility. 819 s.pushTunables() 820 defer s.popTunables() 821 s.precludeSelectedTypes(PointerTfIdx) 822 target := s.GenParm(f, 0, false, pidx) 823 target.SetBlank(false) 824 f.receiver = s.makeTypedefParm(f, target, pidx) 825 if f.receiver.IsBlank() { 826 f.recur = false 827 } 828 } 829 if f.isMethod { 830 genReceiverType() 831 } 832 needControl := f.recur 833 f.dodefc = uint8(s.wr.Intn(100)) 834 pTaken := uint8(s.wr.Intn(100)) < s.tunables.takenFraction 835 for pi := 0; pi < numParams; pi++ { 836 newparm := s.GenParm(f, 0, needControl, pidx) 837 if !pTaken { 838 newparm.SetAddrTaken(notAddrTaken) 839 } 840 if newparm.IsControl() { 841 needControl = false 842 } 843 f.params = append(f.params, newparm) 844 f.dodefp = append(f.dodefp, uint8(s.wr.Intn(100))) 845 } 846 if f.recur && needControl { 847 f.recur = false 848 } 849 850 rTaken := uint8(s.wr.Intn(100)) < s.tunables.takenFraction 851 for ri := 0; ri < numReturns; ri++ { 852 r := s.GenReturn(f, 0, pidx) 853 if !rTaken { 854 r.SetAddrTaken(notAddrTaken) 855 } 856 f.returns = append(f.returns, r) 857 } 858 spw := uint(s.wr.Intn(11)) 859 rstack := 1 << spw 860 if rstack < 4 { 861 rstack = 4 862 } 863 f.rstack = rstack 864 return f 865 } 866 867 func genDeref(p parm) (parm, string) { 868 curp := p 869 star := "" 870 for { 871 if pp, ok := curp.(*pointerparm); ok { 872 star += "*" 873 curp = pp.totype 874 } else { 875 return curp, star 876 } 877 } 878 } 879 880 func (s *genstate) eqFuncRef(f *funcdef, t parm, caller bool) string { 881 cp := "" 882 if f.mapkeyts != "" { 883 cp = "mkt." 884 } else if caller { 885 cp = s.checkerPkg(s.pkidx) + "." 886 } 887 return cp + "Equal" + t.TypeName() 888 } 889 890 // emitCompareFunc creates an 'equals' function for a specific 891 // generated type (this is basically a way to compare objects that 892 // contain pointer fields / pointery things). 893 func (s *genstate) emitCompareFunc(f *funcdef, b *bytes.Buffer, p parm) { 894 if !p.HasPointer() { 895 return 896 } 897 898 tn := p.TypeName() 899 b.WriteString(fmt.Sprintf("// equal func for %s\n", tn)) 900 b.WriteString("//go:noinline\n") 901 rcvr := "" 902 if f.mapkeyts != "" { 903 rcvr = fmt.Sprintf("(mkt *%s) ", f.mapkeyts) 904 } 905 b.WriteString(fmt.Sprintf("func %sEqual%s(left %s, right %s) bool {\n", rcvr, tn, tn, tn)) 906 b.WriteString(" return ") 907 numel := p.NumElements() 908 ncmp := 0 909 for i := 0; i < numel; i++ { 910 lelref, lelparm := p.GenElemRef(i, "left") 911 relref, _ := p.GenElemRef(i, "right") 912 if lelref == "" || lelref == "_" { 913 continue 914 } 915 basep, star := genDeref(lelparm) 916 // Handle *p where p is an empty struct. 917 if basep.NumElements() == 0 { 918 continue 919 } 920 if ncmp != 0 { 921 b.WriteString(" && ") 922 } 923 ncmp++ 924 if basep.HasPointer() { 925 efn := s.eqFuncRef(f, basep, false) 926 b.WriteString(fmt.Sprintf(" %s(%s%s, %s%s)", efn, star, lelref, star, relref)) 927 } else { 928 b.WriteString(fmt.Sprintf("%s%s == %s%s", star, lelref, star, relref)) 929 } 930 } 931 if ncmp == 0 { 932 b.WriteString("true") 933 } 934 b.WriteString("\n}\n\n") 935 } 936 937 // emitStructAndArrayDefs writes out definitions of the random types 938 // we happened to cook up while generating code for a specific 939 // function pair. 940 func (s *genstate) emitStructAndArrayDefs(f *funcdef, b *bytes.Buffer) { 941 for _, str := range f.structdefs { 942 b.WriteString(fmt.Sprintf("type %s struct {\n", str.sname)) 943 for fi, sp := range str.fields { 944 sp.Declare(b, " "+str.FieldName(fi), "\n", false) 945 } 946 b.WriteString("}\n\n") 947 s.emitCompareFunc(f, b, &str) 948 } 949 for _, a := range f.arraydefs { 950 elems := fmt.Sprintf("%d", a.nelements) 951 if a.slice { 952 elems = "" 953 } 954 b.WriteString(fmt.Sprintf("type %s [%s]%s\n\n", a.aname, 955 elems, a.eltype.TypeName())) 956 s.emitCompareFunc(f, b, &a) 957 } 958 for _, a := range f.mapdefs { 959 b.WriteString(fmt.Sprintf("type %s map[%s]%s\n\n", a.aname, 960 a.keytype.TypeName(), a.valtype.TypeName())) 961 s.emitCompareFunc(f, b, &a) 962 } 963 for _, td := range f.typedefs { 964 b.WriteString(fmt.Sprintf("type %s %s\n\n", td.aname, 965 td.target.TypeName())) 966 s.emitCompareFunc(f, b, &td) 967 } 968 if f.mapkeyts != "" { 969 b.WriteString(fmt.Sprintf("type %s struct {\n", f.mapkeyts)) 970 for i := range f.mapkeytypes { 971 f.mapkeytypes[i].Declare(b, " "+f.mapkeytmps[i], "\n", false) 972 } 973 b.WriteString("}\n\n") 974 } 975 } 976 977 // GenValue method of genstate wraps the parm method of the same 978 // name, but optionally returns a call to a function to produce 979 // the value as opposed to a literal value. 980 func (s *genstate) GenValue(f *funcdef, p parm, value int, caller bool) (string, int) { 981 var valstr string 982 valstr, value = p.GenValue(s, f, value, caller) 983 if !s.tunables.doFuncCallValues || !p.IsGenVal() || caller { 984 return valstr, value 985 } 986 987 mkInvoc := func(fname string) string { 988 meth := "" 989 if f.mapkeyts != "" { 990 meth = "mkt." 991 } 992 return fmt.Sprintf("%s%s()", meth, fname) 993 } 994 995 b := bytes.NewBuffer(nil) 996 p.Declare(b, "x", "", false) 997 h := sha1.New() 998 h.Write([]byte(valstr)) 999 h.Write(b.Bytes()) 1000 if f.mapkeyts != "" { 1001 h.Write([]byte(f.mapkeyts)) 1002 } 1003 h.Write(b.Bytes()) 1004 bs := h.Sum(nil) 1005 hashstr := fmt.Sprintf("%x", bs) 1006 b.WriteString(hashstr) 1007 tag := b.String() 1008 fname, ok := s.genvalFuncs[tag] 1009 if ok { 1010 return mkInvoc(fname), value 1011 } 1012 1013 fname = fmt.Sprintf("genval_%d", len(s.genvalFuncs)) 1014 s.newGenvalFuncs = append(s.newGenvalFuncs, funcdesc{p: p, name: fname, tag: tag, payload: valstr}) 1015 s.genvalFuncs[tag] = fname 1016 return mkInvoc(fname), value 1017 } 1018 1019 func (s *genstate) emitMapKeyTmps(f *funcdef, b *bytes.Buffer, pidx int, value int, caller bool) int { 1020 if f.mapkeyts == "" { 1021 return value 1022 } 1023 // map key tmps 1024 cp := "" 1025 if caller { 1026 cp = s.checkerPkg(pidx) + "." 1027 } 1028 b.WriteString(" var mkt " + cp + f.mapkeyts + "\n") 1029 for i, t := range f.mapkeytypes { 1030 var keystr string 1031 keystr, value = s.GenValue(f, t, value, caller) 1032 tname := f.mapkeytmps[i] 1033 b.WriteString(fmt.Sprintf(" %s := %s\n", tname, keystr)) 1034 b.WriteString(fmt.Sprintf(" mkt.%s = %s\n", tname, tname)) 1035 } 1036 return value 1037 } 1038 1039 func (s *genstate) emitCheckReturnsInCaller(f *funcdef, b *bytes.Buffer, pidx int, reflectCall bool) { 1040 cm := f.complexityMeasure() 1041 rvalp := func(ri int) string { 1042 if reflectCall { 1043 return fmt.Sprintf("rr%dv", ri) 1044 } 1045 return fmt.Sprintf("r%d", ri) 1046 } 1047 failTag := "\"return\"" 1048 if reflectCall { 1049 failTag = "\"reflect return\"" 1050 } 1051 for ri, rp := range f.returns { 1052 if reflectCall { 1053 b.WriteString(fmt.Sprintf(" rr%di := rvslice[%d].Interface()\n", ri, ri)) 1054 b.WriteString(fmt.Sprintf(" rr%dv:= rr%di.(", ri, ri)) 1055 rp.Declare(b, "", "", true) 1056 b.WriteString(")\n") 1057 } 1058 pfc := "" 1059 curp, star := genDeref(rp) 1060 // Handle *p where p is an empty struct. 1061 if curp.NumElements() == 0 { 1062 b.WriteString(fmt.Sprintf(" _, _ = %s, c%d // zero size\n", rvalp(ri), ri)) 1063 continue 1064 } 1065 if star != "" { 1066 pfc = fmt.Sprintf("ParamFailCount[%d] == 0 && ", pidx) 1067 } 1068 if curp.HasPointer() { 1069 efn := "!" + s.eqFuncRef(f, curp, true) 1070 b.WriteString(fmt.Sprintf(" if %s%s(%s%s, %sc%d) {\n", pfc, efn, star, rvalp(ri), star, ri)) 1071 } else { 1072 b.WriteString(fmt.Sprintf(" if %s%s%s != %sc%d {\n", pfc, star, rvalp(ri), star, ri)) 1073 } 1074 b.WriteString(fmt.Sprintf(" NoteFailure(%d, %d, %d, \"%s\", %s, %d, true, uint64(0))\n", cm, pidx, f.idx, s.checkerPkg(pidx), failTag, ri)) 1075 b.WriteString(" }\n") 1076 } 1077 } 1078 1079 func (s *genstate) emitCaller(f *funcdef, b *bytes.Buffer, pidx int) { 1080 1081 b.WriteString(fmt.Sprintf("func %s%d(mode string) {\n", CallerName, f.idx)) 1082 1083 b.WriteString(fmt.Sprintf(" BeginFcn(%d)\n", pidx)) 1084 1085 if s.EmitBad == 1 { 1086 if s.BadPackageIdx == pidx && s.BadFuncIdx == f.idx { 1087 b.WriteString(" bad code here, should cause build failure <<==\n") 1088 } 1089 } 1090 1091 var value int = 1 1092 1093 s.wr.Checkpoint("before mapkeytmps") 1094 value = s.emitMapKeyTmps(f, b, pidx, value, true) 1095 1096 // generate return constants 1097 s.wr.Checkpoint("before return constants") 1098 for ri, r := range f.returns { 1099 rc := fmt.Sprintf("c%d", ri) 1100 value = s.emitVarAssign(f, b, r, rc, value, true) 1101 } 1102 1103 // generate param constants 1104 s.wr.Checkpoint("before param constants") 1105 for pi, p := range f.params { 1106 verb(4, "emitCaller gen p%d value=%d", pi, value) 1107 if p.IsControl() { 1108 _ = uint8(s.wr.Intn(100)) < 50 1109 p.Declare(b, fmt.Sprintf(" var p%d ", pi), " = 10\n", true) 1110 } else { 1111 pc := fmt.Sprintf("p%d", pi) 1112 value = s.emitVarAssign(f, b, p, pc, value, true) 1113 } 1114 f.values = append(f.values, value) 1115 } 1116 1117 // generate receiver constant if applicable 1118 if f.isMethod { 1119 s.wr.Checkpoint("before receiver constant") 1120 f.receiver.Declare(b, " var rcvr", "\n", true) 1121 valstr, value := s.GenValue(f, f.receiver, value, true) 1122 b.WriteString(fmt.Sprintf(" rcvr = %s\n", valstr)) 1123 f.values = append(f.values, value) 1124 } 1125 1126 b.WriteString(fmt.Sprintf(" Mode[%d] = \"\"\n", pidx)) 1127 1128 // calling code 1129 b.WriteString(fmt.Sprintf(" // %d returns %d params\n", 1130 len(f.returns), len(f.params))) 1131 if s.ForceStackGrowth { 1132 b.WriteString(" hackStack() // force stack growth on next call\n") 1133 } 1134 b.WriteString(" if mode == \"normal\" {\n") 1135 b.WriteString(" ") 1136 for ri := range f.returns { 1137 writeCom(b, ri) 1138 b.WriteString(fmt.Sprintf("r%d", ri)) 1139 } 1140 if len(f.returns) > 0 { 1141 b.WriteString(" := ") 1142 } 1143 pref := s.checkerPkg(pidx) 1144 if f.isMethod { 1145 pref = "rcvr" 1146 } 1147 b.WriteString(fmt.Sprintf("%s.Test%d(", pref, f.idx)) 1148 for pi := range f.params { 1149 writeCom(b, pi) 1150 b.WriteString(fmt.Sprintf("p%d", pi)) 1151 } 1152 b.WriteString(")\n") 1153 1154 // check values returned (normal call case) 1155 s.emitCheckReturnsInCaller(f, b, pidx, false /* not a reflect call */) 1156 b.WriteString(" }") // end of 'if normal call' block 1157 if s.tunables.doReflectCall { 1158 b.WriteString("else {\n") // beginning of reflect call block 1159 // now make the same call via reflection 1160 b.WriteString(" // same call via reflection\n") 1161 b.WriteString(fmt.Sprintf(" Mode[%d] = \"reflect\"\n", pidx)) 1162 if f.isMethod { 1163 b.WriteString(" rcv := reflect.ValueOf(rcvr)\n") 1164 b.WriteString(fmt.Sprintf(" rc := rcv.MethodByName(\"Test%d\")\n", f.idx)) 1165 } else { 1166 b.WriteString(fmt.Sprintf(" rc := reflect.ValueOf(%s.Test%d)\n", 1167 s.checkerPkg(pidx), f.idx)) 1168 } 1169 b.WriteString(" ") 1170 if len(f.returns) > 0 { 1171 b.WriteString("rvslice := ") 1172 } 1173 b.WriteString(" rc.Call([]reflect.Value{") 1174 for pi := range f.params { 1175 writeCom(b, pi) 1176 b.WriteString(fmt.Sprintf("reflect.ValueOf(p%d)", pi)) 1177 } 1178 b.WriteString("})\n") 1179 1180 // check values returned (reflect call case) 1181 s.emitCheckReturnsInCaller(f, b, pidx, true /* is a reflect call */) 1182 b.WriteString("}\n") // end of reflect call block 1183 } 1184 1185 b.WriteString(fmt.Sprintf("\n EndFcn(%d)\n", pidx)) 1186 1187 b.WriteString("}\n\n") 1188 } 1189 1190 func checkableElements(p parm) int { 1191 if p.IsBlank() { 1192 return 0 1193 } 1194 sp, isstruct := p.(*structparm) 1195 if isstruct { 1196 s := 0 1197 for fi := range sp.fields { 1198 s += checkableElements(sp.fields[fi]) 1199 } 1200 return s 1201 } 1202 ap, isarray := p.(*arrayparm) 1203 if isarray { 1204 if ap.nelements == 0 { 1205 return 0 1206 } 1207 return int(ap.nelements) * checkableElements(ap.eltype) 1208 } 1209 return 1 1210 } 1211 1212 // funcdesc describes an auto-generated helper function or global 1213 // variable, such as an allocation function (returns new(T)) or a 1214 // pointer assignment function (assigns value of T to type *T). Here 1215 // 'p' is a param type T, 'pp' is a pointer type *T, 'name' is the 1216 // name within the generated code of the function or variable and 1217 // 'tag' is a descriptive tag used to look up the entity in a map (so 1218 // that we don't have to emit multiple copies of a function that 1219 // assigns int to *int, for example). 1220 type funcdesc struct { 1221 p parm 1222 pp parm 1223 name string 1224 tag string 1225 payload string 1226 } 1227 1228 func (s *genstate) emitDerefFuncs(b *bytes.Buffer, emit bool) { 1229 b.WriteString("// dereference helpers\n") 1230 for _, fd := range s.newDerefFuncs { 1231 if !emit { 1232 b.WriteString(fmt.Sprintf("\n// skip derefunc %s\n", fd.name)) 1233 delete(s.derefFuncs, fd.tag) 1234 continue 1235 } 1236 b.WriteString("\n//go:noinline\n") 1237 b.WriteString(fmt.Sprintf("func %s(", fd.name)) 1238 fd.pp.Declare(b, "x", "", false) 1239 b.WriteString(") ") 1240 fd.p.Declare(b, "", "", false) 1241 b.WriteString(" {\n") 1242 b.WriteString(" return *x\n") 1243 b.WriteString("}\n") 1244 } 1245 s.newDerefFuncs = nil 1246 } 1247 1248 func (s *genstate) emitAssignFuncs(b *bytes.Buffer, emit bool) { 1249 b.WriteString("// assign helpers\n") 1250 for _, fd := range s.newAssignFuncs { 1251 if !emit { 1252 b.WriteString(fmt.Sprintf("\n// skip assignfunc %s\n", fd.name)) 1253 delete(s.assignFuncs, fd.tag) 1254 continue 1255 } 1256 b.WriteString("\n//go:noinline\n") 1257 b.WriteString(fmt.Sprintf("func %s(", fd.name)) 1258 fd.pp.Declare(b, "x", "", false) 1259 b.WriteString(", ") 1260 fd.p.Declare(b, "v", "", false) 1261 b.WriteString(") {\n") 1262 b.WriteString(" *x = v\n") 1263 b.WriteString("}\n") 1264 } 1265 s.newAssignFuncs = nil 1266 } 1267 1268 func (s *genstate) emitNewFuncs(b *bytes.Buffer, emit bool) { 1269 b.WriteString("// 'new' funcs\n") 1270 for _, fd := range s.newAllocFuncs { 1271 if !emit { 1272 b.WriteString(fmt.Sprintf("\n// skip newfunc %s\n", fd.name)) 1273 delete(s.allocFuncs, fd.tag) 1274 continue 1275 } 1276 b.WriteString("\n//go:noinline\n") 1277 b.WriteString(fmt.Sprintf("func %s(", fd.name)) 1278 fd.p.Declare(b, "i", "", false) 1279 b.WriteString(") ") 1280 fd.pp.Declare(b, "", "", false) 1281 b.WriteString(" {\n") 1282 b.WriteString(" x := new(") 1283 fd.p.Declare(b, "", "", false) 1284 b.WriteString(")\n") 1285 b.WriteString(" *x = i\n") 1286 b.WriteString(" return x\n") 1287 b.WriteString("}\n\n") 1288 } 1289 s.newAllocFuncs = nil 1290 } 1291 1292 func (s *genstate) emitGlobalVars(b *bytes.Buffer, emit bool) { 1293 b.WriteString("// global vars\n") 1294 for _, fd := range s.newGlobVars { 1295 if !emit { 1296 b.WriteString(fmt.Sprintf("\n// skip gvar %s\n", fd.name)) 1297 delete(s.globVars, fd.tag) 1298 continue 1299 } 1300 b.WriteString("var ") 1301 fd.pp.Declare(b, fd.name, "", false) 1302 b.WriteString("\n") 1303 } 1304 s.newGlobVars = nil 1305 b.WriteString("\n") 1306 } 1307 1308 func (s *genstate) emitGenValFuncs(f *funcdef, b *bytes.Buffer, emit bool) { 1309 b.WriteString("// genval helpers\n") 1310 for _, fd := range s.newGenvalFuncs { 1311 if !emit { 1312 b.WriteString(fmt.Sprintf("\n// skip genvalfunc %s\n", fd.name)) 1313 delete(s.genvalFuncs, fd.tag) 1314 continue 1315 } 1316 b.WriteString("\n//go:noinline\n") 1317 rcvr := "" 1318 if f.mapkeyts != "" { 1319 rcvr = fmt.Sprintf("(mkt *%s) ", f.mapkeyts) 1320 } 1321 b.WriteString(fmt.Sprintf("func %s%s() ", rcvr, fd.name)) 1322 fd.p.Declare(b, "", "", false) 1323 b.WriteString(" {\n") 1324 if f.mapkeyts != "" { 1325 contained := containedParms(fd.p) 1326 for _, cp := range contained { 1327 mp, ismap := cp.(*mapparm) 1328 if ismap { 1329 b.WriteString(fmt.Sprintf(" %s := mkt.%s\n", 1330 mp.keytmp, mp.keytmp)) 1331 b.WriteString(fmt.Sprintf(" _ = %s\n", mp.keytmp)) 1332 } 1333 } 1334 } 1335 b.WriteString(fmt.Sprintf(" return %s\n", fd.payload)) 1336 b.WriteString("}\n") 1337 } 1338 s.newGenvalFuncs = nil 1339 } 1340 1341 func (s *genstate) emitAddrTakenHelpers(f *funcdef, b *bytes.Buffer, emit bool) { 1342 b.WriteString("// begin addr taken helpers\n") 1343 s.emitDerefFuncs(b, emit) 1344 s.emitAssignFuncs(b, emit) 1345 s.emitNewFuncs(b, emit) 1346 s.emitGlobalVars(b, emit) 1347 s.emitGenValFuncs(f, b, emit) 1348 b.WriteString("// end addr taken helpers\n") 1349 } 1350 1351 func (s *genstate) genGlobVar(p parm) string { 1352 var pp parm 1353 ppp := mkPointerParm(p) 1354 pp = &ppp 1355 b := bytes.NewBuffer(nil) 1356 pp.Declare(b, "gv", "", false) 1357 tag := b.String() 1358 gv, ok := s.globVars[tag] 1359 if ok { 1360 return gv 1361 } 1362 gv = fmt.Sprintf("gvar_%d", len(s.globVars)) 1363 s.newGlobVars = append(s.newGlobVars, funcdesc{pp: pp, p: p, name: gv, tag: tag}) 1364 s.globVars[tag] = gv 1365 return gv 1366 } 1367 1368 func (s *genstate) genParamDerefFunc(p parm) string { 1369 var pp parm 1370 ppp := mkPointerParm(p) 1371 pp = &ppp 1372 b := bytes.NewBuffer(nil) 1373 pp.Declare(b, "x", "", false) 1374 tag := b.String() 1375 f, ok := s.derefFuncs[tag] 1376 if ok { 1377 return f 1378 } 1379 f = fmt.Sprintf("deref_%d", len(s.derefFuncs)) 1380 s.newDerefFuncs = append(s.newDerefFuncs, funcdesc{pp: pp, p: p, name: f, tag: tag}) 1381 s.derefFuncs[tag] = f 1382 return f 1383 } 1384 1385 func (s *genstate) genAssignFunc(p parm) string { 1386 var pp parm 1387 ppp := mkPointerParm(p) 1388 pp = &ppp 1389 b := bytes.NewBuffer(nil) 1390 pp.Declare(b, "x", "", false) 1391 tag := b.String() 1392 f, ok := s.assignFuncs[tag] 1393 if ok { 1394 return f 1395 } 1396 f = fmt.Sprintf("retassign_%d", len(s.assignFuncs)) 1397 s.newAssignFuncs = append(s.newAssignFuncs, funcdesc{pp: pp, p: p, name: f, tag: tag}) 1398 s.assignFuncs[tag] = f 1399 return f 1400 } 1401 1402 func (s *genstate) genAllocFunc(p parm) string { 1403 var pp parm 1404 ppp := mkPointerParm(p) 1405 pp = &ppp 1406 b := bytes.NewBuffer(nil) 1407 pp.Declare(b, "x", "", false) 1408 tag := b.String() 1409 f, ok := s.allocFuncs[tag] 1410 if ok { 1411 return f 1412 } 1413 f = fmt.Sprintf("New_%d", len(s.allocFuncs)) 1414 s.newAllocFuncs = append(s.newAllocFuncs, funcdesc{pp: pp, p: p, name: f, tag: tag}) 1415 s.allocFuncs[tag] = f 1416 return f 1417 } 1418 1419 func (s *genstate) genParamRef(p parm, idx int) string { 1420 switch p.AddrTaken() { 1421 case notAddrTaken: 1422 return fmt.Sprintf("p%d", idx) 1423 case addrTakenSimple, addrTakenHeap: 1424 return fmt.Sprintf("(*ap%d)", idx) 1425 case addrTakenPassed: 1426 f := s.genParamDerefFunc(p) 1427 return fmt.Sprintf("%s(ap%d)", f, idx) 1428 default: 1429 panic("bad") 1430 } 1431 } 1432 1433 func (s *genstate) genReturnAssign(b *bytes.Buffer, r parm, idx int, val string) { 1434 switch r.AddrTaken() { 1435 case notAddrTaken: 1436 b.WriteString(fmt.Sprintf(" r%d = %s\n", idx, val)) 1437 case addrTakenSimple, addrTakenHeap: 1438 b.WriteString(fmt.Sprintf(" (*ar%d) = %v\n", idx, val)) 1439 case addrTakenPassed: 1440 f := s.genAssignFunc(r) 1441 b.WriteString(fmt.Sprintf(" %s(ar%d, %v)\n", f, idx, val)) 1442 default: 1443 panic("bad") 1444 } 1445 } 1446 1447 func (s *genstate) emitParamElemCheck(f *funcdef, b *bytes.Buffer, p parm, pvar string, cvar string, paramidx int, elemidx int) { 1448 if p.SkipCompare() == SkipAll { 1449 b.WriteString(fmt.Sprintf(" // selective skip of %s\n", pvar)) 1450 b.WriteString(fmt.Sprintf(" _ = %s\n", cvar)) 1451 return 1452 } else if p.SkipCompare() == SkipPayload { 1453 switch p.(type) { 1454 case *stringparm, *arrayparm: 1455 b.WriteString(fmt.Sprintf(" if len(%s) != len(%s) { // skip payload\n", 1456 pvar, cvar)) 1457 default: 1458 panic("should never happen") 1459 } 1460 } else { 1461 basep, star := genDeref(p) 1462 // Handle *p where p is an empty struct. 1463 if basep.NumElements() == 0 { 1464 return 1465 } 1466 if basep.HasPointer() { 1467 efn := s.eqFuncRef(f, basep, false) 1468 b.WriteString(fmt.Sprintf(" if !%s(%s%s, %s%s) {\n", 1469 efn, star, pvar, star, cvar)) 1470 } else { 1471 b.WriteString(fmt.Sprintf(" if %s%s != %s%s {\n", 1472 star, pvar, star, cvar)) 1473 } 1474 } 1475 cm := f.complexityMeasure() 1476 b.WriteString(fmt.Sprintf(" NoteFailureElem(%d, %d, %d, \"%s\", \"parm\", %d, %d, false, pad[0])\n", cm, s.pkidx, f.idx, s.checkerPkg(s.pkidx), paramidx, elemidx)) 1477 b.WriteString(" return\n") 1478 b.WriteString(" }\n") 1479 } 1480 1481 func (s *genstate) emitParamChecks(f *funcdef, b *bytes.Buffer, pidx int, value int) (int, bool) { 1482 var valstr string 1483 haveControl := false 1484 dangling := []int{} 1485 for pi, p := range f.params { 1486 verb(4, "emitting parmcheck p%d numel=%d pt=%s value=%d", 1487 pi, p.NumElements(), p.TypeName(), value) 1488 // To balance code in caller 1489 _ = uint8(s.wr.Intn(100)) < 50 1490 if p.IsControl() { 1491 b.WriteString(fmt.Sprintf(" if %s == 0 {\n", 1492 s.genParamRef(p, pi))) 1493 s.emitReturn(f, b, false) 1494 b.WriteString(" }\n") 1495 haveControl = true 1496 1497 } else if p.IsBlank() { 1498 valstr, value = s.GenValue(f, p, value, false) 1499 if f.recur { 1500 b.WriteString(fmt.Sprintf(" brc%d := %s\n", pi, valstr)) 1501 } else { 1502 b.WriteString(fmt.Sprintf(" _ = %s\n", valstr)) 1503 } 1504 } else { 1505 numel := p.NumElements() 1506 cel := checkableElements(p) 1507 for i := 0; i < numel; i++ { 1508 verb(4, "emitting check-code for p%d el %d value=%d", pi, i, value) 1509 elref, elparm := p.GenElemRef(i, s.genParamRef(p, pi)) 1510 valstr, value = s.GenValue(f, elparm, value, false) 1511 if elref == "" || elref == "_" || cel == 0 { 1512 b.WriteString(fmt.Sprintf(" // blank skip: %s\n", valstr)) 1513 continue 1514 } else { 1515 basep, _ := genDeref(elparm) 1516 // Handle *p where p is an empty struct. 1517 if basep.NumElements() == 0 { 1518 continue 1519 } 1520 cvar := fmt.Sprintf("p%df%dc", pi, i) 1521 b.WriteString(fmt.Sprintf(" %s := %s\n", cvar, valstr)) 1522 s.emitParamElemCheck(f, b, elparm, elref, cvar, pi, i) 1523 } 1524 } 1525 if p.AddrTaken() != notAddrTaken { 1526 dangling = append(dangling, pi) 1527 } 1528 } 1529 if value != f.values[pi] { 1530 fmt.Fprintf(os.Stderr, "internal error: checker/caller value mismatch after emitting param %d func Test%d pkg %s: caller %d checker %d\n", pi, f.idx, s.checkerPkg(pidx), f.values[pi], value) 1531 s.errs++ 1532 } 1533 } 1534 for _, pi := range dangling { 1535 b.WriteString(fmt.Sprintf(" _ = ap%d // ref\n", pi)) 1536 } 1537 1538 // receiver value check 1539 if f.isMethod { 1540 numel := f.receiver.NumElements() 1541 for i := 0; i < numel; i++ { 1542 verb(4, "emitting check-code for rcvr el %d value=%d", i, value) 1543 elref, elparm := f.receiver.GenElemRef(i, "rcvr") 1544 valstr, value = s.GenValue(f, elparm, value, false) 1545 if elref == "" || strings.HasPrefix(elref, "_") || f.receiver.IsBlank() { 1546 verb(4, "empty skip rcvr el %d", i) 1547 continue 1548 } else { 1549 1550 basep, _ := genDeref(elparm) 1551 // Handle *p where p is an empty struct. 1552 if basep.NumElements() == 0 { 1553 continue 1554 } 1555 cvar := fmt.Sprintf("rcvrf%dc", i) 1556 b.WriteString(fmt.Sprintf(" %s := %s\n", cvar, valstr)) 1557 s.emitParamElemCheck(f, b, elparm, elref, cvar, -1, i) 1558 } 1559 } 1560 } 1561 1562 return value, haveControl 1563 } 1564 1565 // emitDeferChecks creates code like 1566 // 1567 // defer func(...args...) { 1568 // check arg 1569 // check param 1570 // }(...) 1571 // 1572 // where we randomly choose to either pass a param through to the 1573 // function literal, or have the param captured by the closure, then 1574 // check its value in the defer. 1575 func (s *genstate) emitDeferChecks(f *funcdef, b *bytes.Buffer, pidx int, value int) int { 1576 1577 if len(f.params) == 0 { 1578 return value 1579 } 1580 1581 // make a pass through the params and randomly decide which will be passed into the func. 1582 passed := []bool{} 1583 for i := range f.params { 1584 p := f.dodefp[i] < 50 1585 passed = append(passed, p) 1586 } 1587 1588 b.WriteString(" defer func(") 1589 pc := 0 1590 for pi, p := range f.params { 1591 if p.IsControl() || p.IsBlank() { 1592 continue 1593 } 1594 if passed[pi] { 1595 writeCom(b, pc) 1596 n := fmt.Sprintf("p%d", pi) 1597 p.Declare(b, n, "", false) 1598 pc++ 1599 } 1600 } 1601 b.WriteString(") {\n") 1602 1603 for pi, p := range f.params { 1604 if p.IsControl() || p.IsBlank() { 1605 continue 1606 } 1607 which := "passed" 1608 if !passed[pi] { 1609 which = "captured" 1610 } 1611 b.WriteString(" // check parm " + which + "\n") 1612 numel := p.NumElements() 1613 cel := checkableElements(p) 1614 for i := 0; i < numel; i++ { 1615 elref, elparm := p.GenElemRef(i, s.genParamRef(p, pi)) 1616 if elref == "" || elref == "_" || cel == 0 { 1617 verb(4, "empty skip p%d el %d", pi, i) 1618 continue 1619 } else { 1620 basep, _ := genDeref(elparm) 1621 // Handle *p where p is an empty struct. 1622 if basep.NumElements() == 0 { 1623 continue 1624 } 1625 cvar := fmt.Sprintf("p%df%dc", pi, i) 1626 s.emitParamElemCheck(f, b, elparm, elref, cvar, pi, i) 1627 } 1628 } 1629 } 1630 b.WriteString(" } (") 1631 pc = 0 1632 for pi, p := range f.params { 1633 if p.IsControl() || p.IsBlank() { 1634 continue 1635 } 1636 if passed[pi] { 1637 writeCom(b, pc) 1638 b.WriteString(fmt.Sprintf("p%d", pi)) 1639 pc++ 1640 } 1641 } 1642 b.WriteString(")\n\n") 1643 1644 return value 1645 } 1646 1647 func (s *genstate) emitVarAssign(f *funcdef, b *bytes.Buffer, r parm, rname string, value int, caller bool) int { 1648 var valstr string 1649 isassign := uint8(s.wr.Intn(100)) < 50 1650 if rmp, ismap := r.(*mapparm); ismap && isassign { 1651 // emit: var m ... ; m[k] = v 1652 r.Declare(b, " "+rname+" := make(", ")\n", caller) 1653 valstr, value = s.GenValue(f, rmp.valtype, value, caller) 1654 b.WriteString(fmt.Sprintf(" %s[mkt.%s] = %s\n", 1655 rname, rmp.keytmp, valstr)) 1656 } else { 1657 // emit r = c 1658 valstr, value = s.GenValue(f, r, value, caller) 1659 b.WriteString(fmt.Sprintf(" %s := %s\n", rname, valstr)) 1660 } 1661 return value 1662 } 1663 1664 func (s *genstate) emitChecker(f *funcdef, b *bytes.Buffer, pidx int, emit bool) { 1665 verb(4, "emitting struct and array defs") 1666 s.emitStructAndArrayDefs(f, b) 1667 b.WriteString(fmt.Sprintf("// %d returns %d params\n", len(f.returns), len(f.params))) 1668 if s.Pragma != "" { 1669 b.WriteString("//go:" + s.Pragma + "\n") 1670 } 1671 b.WriteString("//go:noinline\n") 1672 1673 b.WriteString("func") 1674 1675 if f.isMethod { 1676 b.WriteString(" (") 1677 n := "rcvr" 1678 if f.receiver.IsBlank() { 1679 n = "_" 1680 } 1681 f.receiver.Declare(b, n, "", false) 1682 b.WriteString(")") 1683 } 1684 1685 b.WriteString(fmt.Sprintf(" Test%d(", f.idx)) 1686 1687 verb(4, "emitting checker p%d/Test%d", pidx, f.idx) 1688 1689 // params 1690 for pi, p := range f.params { 1691 writeCom(b, pi) 1692 n := fmt.Sprintf("p%d", pi) 1693 if p.IsBlank() { 1694 n = "_" 1695 } 1696 p.Declare(b, n, "", false) 1697 } 1698 b.WriteString(") ") 1699 1700 // returns 1701 if len(f.returns) > 0 { 1702 b.WriteString("(") 1703 } 1704 for ri, r := range f.returns { 1705 writeCom(b, ri) 1706 r.Declare(b, fmt.Sprintf("r%d", ri), "", false) 1707 } 1708 if len(f.returns) > 0 { 1709 b.WriteString(")") 1710 } 1711 b.WriteString(" {\n") 1712 1713 // local storage 1714 b.WriteString(" // consume some stack space, so as to trigger morestack\n") 1715 b.WriteString(fmt.Sprintf(" var pad [%d]uint64\n", f.rstack)) 1716 b.WriteString(fmt.Sprintf(" pad[FailCount[%d] & 0x1]++\n", pidx)) 1717 1718 value := 1 1719 1720 // generate map key tmps 1721 s.wr.Checkpoint("before map key temps") 1722 value = s.emitMapKeyTmps(f, b, pidx, value, false) 1723 1724 // generate return constants 1725 s.wr.Checkpoint("before return constants") 1726 for ri, r := range f.returns { 1727 rc := fmt.Sprintf("rc%d", ri) 1728 value = s.emitVarAssign(f, b, r, rc, value, false) 1729 } 1730 1731 // Prepare to reference params/returns by address. 1732 lists := [][]parm{f.params, f.returns} 1733 names := []string{"p", "r"} 1734 var aCounts [2]int 1735 for i, lst := range lists { 1736 for pi, p := range lst { 1737 if p.AddrTaken() == notAddrTaken { 1738 continue 1739 } 1740 aCounts[i]++ 1741 n := names[i] 1742 b.WriteString(fmt.Sprintf(" a%s%d := &%s%d\n", n, pi, n, pi)) 1743 if p.AddrTaken() == addrTakenHeap { 1744 gv := s.genGlobVar(p) 1745 b.WriteString(fmt.Sprintf(" %s = a%s%d\n", gv, n, pi)) 1746 } 1747 } 1748 } 1749 1750 if s.EmitBad == 2 { 1751 if s.BadPackageIdx == pidx && s.BadFuncIdx == f.idx { 1752 b.WriteString(" // force runtime failure here (debugging)\n") 1753 b.WriteString(fmt.Sprintf(" NoteFailure(%d, %d, %d, \"%s\", \"artificial\", %d, true, uint64(0))\n", f.complexityMeasure(), pidx, f.idx, s.checkerPkg(pidx), 0)) 1754 } 1755 } 1756 1757 // parameter checking code 1758 var haveControl bool 1759 s.wr.Checkpoint("before param checks") 1760 value, haveControl = s.emitParamChecks(f, b, pidx, value) 1761 1762 // defer testing 1763 if s.tunables.doDefer && f.dodefc < s.tunables.deferFraction { 1764 s.wr.Checkpoint("before defer checks") 1765 _ = s.emitDeferChecks(f, b, pidx, value) 1766 } 1767 1768 // returns 1769 s.emitReturn(f, b, haveControl) 1770 1771 b.WriteString(fmt.Sprintf(" // %d addr-taken params, %d addr-taken returns\n", 1772 aCounts[0], aCounts[1])) 1773 1774 b.WriteString("}\n\n") 1775 1776 // emit any new helper funcs referenced by this test function 1777 s.emitAddrTakenHelpers(f, b, emit) 1778 } 1779 1780 // complexityMeasure returns an integer that estimates how complex a 1781 // given test function is relative to some other function. The more 1782 // parameters + returns and the more complicated the types of the 1783 // params/returns, the higher the number returned here. In theory this 1784 // could be worked into the minimization process (e.g. pick the least 1785 // complex func that reproduces the failure), but for now that isn't 1786 // wired up yet. 1787 func (f *funcdef) complexityMeasure() int { 1788 v := int(0) 1789 if f.isMethod { 1790 v += f.receiver.NumElements() 1791 } 1792 for _, p := range f.params { 1793 v += p.NumElements() 1794 } 1795 for _, r := range f.returns { 1796 v += r.NumElements() 1797 } 1798 return v 1799 } 1800 1801 // emitRecursiveCall generates a recursive call to the test function in question. 1802 func (s *genstate) emitRecursiveCall(f *funcdef) string { 1803 b := bytes.NewBuffer(nil) 1804 rcvr := "" 1805 if f.isMethod { 1806 rcvr = "rcvr." 1807 } 1808 b.WriteString(fmt.Sprintf(" %sTest%d(", rcvr, f.idx)) 1809 for pi, p := range f.params { 1810 writeCom(b, pi) 1811 if p.IsControl() { 1812 b.WriteString(fmt.Sprintf(" %s-1", s.genParamRef(p, pi))) 1813 } else { 1814 if !p.IsBlank() { 1815 b.WriteString(fmt.Sprintf(" %s", s.genParamRef(p, pi))) 1816 } else { 1817 b.WriteString(fmt.Sprintf(" brc%d", pi)) 1818 } 1819 } 1820 } 1821 b.WriteString(")") 1822 return b.String() 1823 } 1824 1825 // emitReturn generates a return sequence. 1826 func (s *genstate) emitReturn(f *funcdef, b *bytes.Buffer, doRecursiveCall bool) { 1827 // If any of the return values are address-taken, then instead of 1828 // 1829 // return x, y, z 1830 // 1831 // we emit 1832 // 1833 // r1 = ... 1834 // r2 = ... 1835 // ... 1836 // return 1837 // 1838 // Make an initial pass through the returns to see if we need to do this. 1839 // Figure out the final return values in the process. 1840 indirectReturn := false 1841 retvals := []string{} 1842 for ri, r := range f.returns { 1843 if r.AddrTaken() != notAddrTaken { 1844 indirectReturn = true 1845 } 1846 t := "" 1847 if doRecursiveCall { 1848 t = "t" 1849 } 1850 retvals = append(retvals, fmt.Sprintf("rc%s%d", t, ri)) 1851 } 1852 1853 // generate the recursive call itself if applicable 1854 if doRecursiveCall { 1855 b.WriteString(" // recursive call\n ") 1856 if s.ForceStackGrowth { 1857 b.WriteString(" hackStack() // force stack growth on next call\n") 1858 } 1859 rcall := s.emitRecursiveCall(f) 1860 if indirectReturn { 1861 for ri := range f.returns { 1862 writeCom(b, ri) 1863 b.WriteString(fmt.Sprintf(" rct%d", ri)) 1864 } 1865 b.WriteString(" := ") 1866 b.WriteString(rcall) 1867 b.WriteString("\n") 1868 } else { 1869 if len(f.returns) == 0 { 1870 b.WriteString(fmt.Sprintf("%s\n return\n", rcall)) 1871 } else { 1872 b.WriteString(fmt.Sprintf(" return %s\n", rcall)) 1873 } 1874 return 1875 } 1876 } 1877 1878 // now the actual return 1879 if indirectReturn { 1880 for ri, r := range f.returns { 1881 s.genReturnAssign(b, r, ri, retvals[ri]) 1882 } 1883 b.WriteString(" return\n") 1884 } else { 1885 b.WriteString(" return ") 1886 for ri := range f.returns { 1887 writeCom(b, ri) 1888 b.WriteString(retvals[ri]) 1889 } 1890 b.WriteString("\n") 1891 } 1892 } 1893 1894 func (s *genstate) GenPair(calloutfile *os.File, checkoutfile *os.File, fidx int, pidx int, b *bytes.Buffer, seed int64, emit bool) int64 { 1895 1896 verb(1, "gen fidx %d pidx %d", fidx, pidx) 1897 1898 checkTunables(tunables) 1899 s.tunables = tunables 1900 1901 // Generate a function with a random number of params and returns 1902 s.wr = NewWrapRand(seed, s.RandCtl) 1903 s.wr.tag = "genfunc" 1904 fp := s.GenFunc(fidx, pidx) 1905 1906 // Emit caller side 1907 wrcaller := NewWrapRand(seed, s.RandCtl) 1908 s.wr = wrcaller 1909 s.wr.tag = "caller" 1910 s.emitCaller(fp, b, pidx) 1911 if emit { 1912 b.WriteTo(calloutfile) 1913 } 1914 b.Reset() 1915 1916 // Emit checker side 1917 wrchecker := NewWrapRand(seed, s.RandCtl) 1918 s.wr = wrchecker 1919 s.wr.tag = "checker" 1920 s.emitChecker(fp, b, pidx, emit) 1921 if emit { 1922 b.WriteTo(checkoutfile) 1923 } 1924 b.Reset() 1925 wrchecker.Check(wrcaller) 1926 1927 return seed + 1 1928 } 1929 1930 func (s *genstate) openOutputFile(filename string, pk string, imports []string, ipref string) *os.File { 1931 iprefix := func(f string) string { 1932 if ipref == "" { 1933 return f 1934 } 1935 return ipref + "/" + f 1936 } 1937 verb(1, "opening %s", filename) 1938 outf, err := os.OpenFile(filename, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 1939 if err != nil { 1940 log.Fatal(err) 1941 } 1942 haveunsafe := false 1943 outf.WriteString(fmt.Sprintf("package %s\n\n", pk)) 1944 for _, imp := range imports { 1945 if imp == "reflect" { 1946 outf.WriteString("import \"reflect\"\n") 1947 continue 1948 } 1949 if imp == "unsafe" { 1950 outf.WriteString("import _ \"unsafe\"\n") 1951 haveunsafe = true 1952 continue 1953 } 1954 if imp == s.utilsPkg() { 1955 1956 outf.WriteString(fmt.Sprintf("import . \"%s\"\n", iprefix(imp))) 1957 continue 1958 } 1959 outf.WriteString(fmt.Sprintf("import \"%s\"\n", iprefix(imp))) 1960 } 1961 outf.WriteString("\n") 1962 if s.ForceStackGrowth && haveunsafe { 1963 outf.WriteString("// Hack: reach into runtime to grab this testing hook.\n") 1964 outf.WriteString("//go:linkname hackStack runtime.gcTestMoveStackOnNextCall\n") 1965 outf.WriteString("func hackStack()\n\n") 1966 } 1967 return outf 1968 } 1969 1970 type miscVals struct { 1971 NumTpk int 1972 MaxFail int 1973 NumTests int 1974 } 1975 1976 const utilsTemplate = ` 1977 1978 import ( 1979 "fmt" 1980 "os" 1981 ) 1982 1983 type UtilsType int 1984 var ParamFailCount [{{.NumTpk}}]int 1985 var ReturnFailCount [{{.NumTpk}}]int 1986 var FailCount [{{.NumTpk}}]int 1987 var Mode [{{.NumTpk}}]string 1988 1989 //go:noinline 1990 func NoteFailure(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, isret bool, _ uint64) { 1991 if isret { 1992 if ParamFailCount[pidx] != 0 { 1993 return 1994 } 1995 ReturnFailCount[pidx]++ 1996 } else { 1997 ParamFailCount[pidx]++ 1998 } 1999 fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo) 2000 2001 if ParamFailCount[pidx]+FailCount[pidx]+ReturnFailCount[pidx] > {{.MaxFail}} { 2002 os.Exit(1) 2003 } 2004 } 2005 2006 //go:noinline 2007 func NoteFailureElem(cm int, pidx int, fidx int, pkg string, pref string, parmNo int, elem int, isret bool, _ uint64) { 2008 2009 if isret { 2010 if ParamFailCount[pidx] != 0 { 2011 return 2012 } 2013 ReturnFailCount[pidx]++ 2014 } else { 2015 ParamFailCount[pidx]++ 2016 } 2017 fmt.Fprintf(os.Stderr, "Error: fail %s |%d|%d|%d| =%s.Test%d= %s %d elem %d\n", Mode, cm, pidx, fidx, pkg, fidx, pref, parmNo, elem) 2018 2019 if ParamFailCount[pidx]+FailCount[pidx]+ReturnFailCount[pidx] > {{.MaxFail}} { 2020 os.Exit(1) 2021 } 2022 } 2023 2024 func BeginFcn(p int) { 2025 ParamFailCount[p] = 0 2026 ReturnFailCount[p] = 0 2027 } 2028 2029 func EndFcn(p int) { 2030 FailCount[p] += ParamFailCount[p] 2031 FailCount[p] += ReturnFailCount[p] 2032 } 2033 ` 2034 2035 func (s *genstate) emitUtils(outf *os.File, maxfail int, numtpk int) { 2036 vals := miscVals{ 2037 NumTpk: numtpk, 2038 MaxFail: maxfail, 2039 } 2040 t := template.Must(template.New("utils").Parse(utilsTemplate)) 2041 err := t.Execute(outf, vals) 2042 if err != nil { 2043 log.Fatal(err) 2044 } 2045 } 2046 2047 const mainPreamble = ` 2048 2049 import ( 2050 "fmt" 2051 "os" 2052 ) 2053 2054 func main() { 2055 fmt.Fprintf(os.Stderr, "starting main\n") 2056 ` 2057 2058 func (s *genstate) emitMain(outf *os.File, numit int, fcnmask map[int]int, pkmask map[int]int) { 2059 fmt.Fprintf(outf, "%s", mainPreamble) 2060 fmt.Fprintf(outf, " pch := make(chan bool, %d)\n", s.NumTestPackages) 2061 for k := 0; k < s.NumTestPackages; k++ { 2062 cp := fmt.Sprintf("%s%s%d", s.Tag, CallerName, k) 2063 fmt.Fprintf(outf, " go func(ch chan bool) {\n") 2064 for i := 0; i < numit; i++ { 2065 if shouldEmitFP(i, k, fcnmask, pkmask) { 2066 fmt.Fprintf(outf, " %s.%s%d(\"normal\")\n", cp, CallerName, i) 2067 if s.tunables.doReflectCall { 2068 fmt.Fprintf(outf, " %s.%s%d(\"reflect\")\n", cp, CallerName, i) 2069 } 2070 } 2071 } 2072 fmt.Fprintf(outf, " pch <- true\n") 2073 fmt.Fprintf(outf, " }(pch)\n") 2074 } 2075 fmt.Fprintf(outf, " for pidx := 0; pidx < %d; pidx++ {\n", s.NumTestPackages) 2076 fmt.Fprintf(outf, " _ = <- pch\n") 2077 fmt.Fprintf(outf, " }\n") 2078 fmt.Fprintf(outf, " tf := 0\n") 2079 fmt.Fprintf(outf, " for pidx := 0; pidx < %d; pidx++ {\n", s.NumTestPackages) 2080 fmt.Fprintf(outf, " tf += FailCount[pidx]\n") 2081 fmt.Fprintf(outf, " }\n") 2082 fmt.Fprintf(outf, " if tf != 0 {\n") 2083 fmt.Fprintf(outf, " fmt.Fprintf(os.Stderr, \"FAILURES: %%d\\n\", tf)\n") 2084 fmt.Fprintf(outf, " os.Exit(2)\n") 2085 fmt.Fprintf(outf, " }\n") 2086 fmt.Fprintf(outf, " fmt.Fprintf(os.Stderr, \"finished %d tests\\n\")\n", numit*s.NumTestPackages) 2087 fmt.Fprintf(outf, "}\n") 2088 } 2089 2090 func makeDir(d string) { 2091 fi, err := os.Stat(d) 2092 if err == nil && fi.IsDir() { 2093 return 2094 } 2095 verb(1, "creating %s", d) 2096 if err := os.Mkdir(d, 0777); err != nil { 2097 log.Fatal(err) 2098 } 2099 } 2100 2101 func (s *genstate) callerPkg(which int) string { 2102 return s.Tag + CallerName + strconv.Itoa(which) 2103 } 2104 2105 func (s *genstate) callerFile(which int) string { 2106 cp := s.callerPkg(which) 2107 return filepath.Join(s.OutDir, cp, cp+".go") 2108 } 2109 2110 func (s *genstate) checkerPkg(which int) string { 2111 return s.Tag + CheckerName + strconv.Itoa(which) 2112 } 2113 2114 func (s *genstate) checkerFile(which int) string { 2115 cp := s.checkerPkg(which) 2116 return filepath.Join(s.OutDir, cp, cp+".go") 2117 } 2118 2119 func (s *genstate) utilsPkg() string { 2120 return s.Tag + "Utils" 2121 } 2122 2123 func (s *genstate) beginPackage(pkidx int) { 2124 s.pkidx = pkidx 2125 s.derefFuncs = make(map[string]string) 2126 s.assignFuncs = make(map[string]string) 2127 s.allocFuncs = make(map[string]string) 2128 s.globVars = make(map[string]string) 2129 s.genvalFuncs = make(map[string]string) 2130 } 2131 2132 func runImports(files []string) { 2133 verb(1, "... running goimports") 2134 args := make([]string, 0, len(files)+1) 2135 args = append(args, "-w") 2136 args = append(args, files...) 2137 cmd := exec.Command("goimports", args...) 2138 coutput, cerr := cmd.CombinedOutput() 2139 if cerr != nil { 2140 log.Fatalf("goimports command failed: %s", string(coutput)) 2141 } 2142 verb(1, "... goimports run complete") 2143 } 2144 2145 // shouldEmitFP returns true if we should actually emit code for the function 2146 // with the specified package + fcn indices. For "regular" runs, fcnmask and pkmask 2147 // will be empty, meaning we want to emit every function in every package. The 2148 // fuzz-runner program also tries to do testcase "minimization", which means that it 2149 // will try to whittle down the set of packages and functions (by running the generator 2150 // using the fcnmask and pkmask options) to emit only specific packages or functions. 2151 func shouldEmitFP(fn int, pk int, fcnmask map[int]int, pkmask map[int]int) bool { 2152 emitpk := true 2153 emitfn := true 2154 if len(pkmask) != 0 { 2155 emitpk = false 2156 if _, ok := pkmask[pk]; ok { 2157 emitpk = true 2158 } 2159 } 2160 if len(fcnmask) != 0 { 2161 emitfn = false 2162 if _, ok := fcnmask[fn]; ok { 2163 emitfn = true 2164 } 2165 } 2166 doemit := emitpk && emitfn 2167 verb(2, "shouldEmitFP(F=%d,P=%d) returns %v", fn, pk, doemit) 2168 return doemit 2169 } 2170 2171 // Generate is the top level code generation hook for this package. 2172 // Emits code according to the schema in config object 'c'. 2173 func Generate(c GenConfig) int { 2174 mainpkg := c.Tag + "Main" 2175 2176 var ipref string 2177 if len(c.PkgPath) > 0 { 2178 ipref = c.PkgPath 2179 } 2180 2181 s := genstate{ 2182 GenConfig: c, 2183 ipref: ipref, 2184 } 2185 2186 if s.OutDir != "." { 2187 verb(1, "creating %s", s.OutDir) 2188 makeDir(s.OutDir) 2189 } 2190 2191 mainimports := []string{} 2192 for i := 0; i < s.NumTestPackages; i++ { 2193 if shouldEmitFP(-1, i, nil, s.PkgMask) { 2194 makeDir(s.OutDir + "/" + s.callerPkg(i)) 2195 makeDir(s.OutDir + "/" + s.checkerPkg(i)) 2196 makeDir(s.OutDir + "/" + s.utilsPkg()) 2197 mainimports = append(mainimports, s.callerPkg(i)) 2198 } 2199 } 2200 mainimports = append(mainimports, s.utilsPkg()) 2201 2202 // Emit utils package. 2203 verb(1, "emit utils") 2204 utilsfile := s.OutDir + "/" + s.utilsPkg() + "/" + s.utilsPkg() + ".go" 2205 utilsoutfile := s.openOutputFile(utilsfile, s.utilsPkg(), []string{}, "") 2206 s.emitUtils(utilsoutfile, s.MaxFail, s.NumTestPackages) 2207 utilsoutfile.Close() 2208 2209 mainfile := s.OutDir + "/" + mainpkg + ".go" 2210 mainoutfile := s.openOutputFile(mainfile, "main", mainimports, ipref) 2211 2212 allfiles := []string{mainfile, utilsfile} 2213 for k := 0; k < s.NumTestPackages; k++ { 2214 callerImports := []string{s.checkerPkg(k), s.utilsPkg()} 2215 checkerImports := []string{s.utilsPkg()} 2216 if tunables.doReflectCall { 2217 callerImports = append(callerImports, "reflect") 2218 } 2219 if s.ForceStackGrowth { 2220 callerImports = append(callerImports, "unsafe") 2221 checkerImports = append(checkerImports, "unsafe") 2222 } 2223 var calleroutfile, checkeroutfile *os.File 2224 if shouldEmitFP(-1, k, nil, s.PkgMask) { 2225 calleroutfile = s.openOutputFile(s.callerFile(k), s.callerPkg(k), 2226 callerImports, ipref) 2227 checkeroutfile = s.openOutputFile(s.checkerFile(k), s.checkerPkg(k), 2228 checkerImports, ipref) 2229 allfiles = append(allfiles, s.callerFile(k), s.checkerFile(k)) 2230 } 2231 2232 s.beginPackage(k) 2233 2234 var b bytes.Buffer 2235 for i := 0; i < s.NumTestFunctions; i++ { 2236 doemit := shouldEmitFP(i, k, s.FcnMask, s.PkgMask) 2237 s.Seed = s.GenPair(calleroutfile, checkeroutfile, i, k, 2238 &b, s.Seed, doemit) 2239 } 2240 2241 // When minimization is in effect, we sometimes wind 2242 // up eliminating all refs to the utils package. Add a 2243 // dummy to help with this. 2244 fmt.Fprintf(calleroutfile, "\n// dummy\nvar Dummy UtilsType\n") 2245 fmt.Fprintf(checkeroutfile, "\n// dummy\nvar Dummy UtilsType\n") 2246 calleroutfile.Close() 2247 checkeroutfile.Close() 2248 } 2249 s.emitMain(mainoutfile, s.NumTestFunctions, s.FcnMask, s.PkgMask) 2250 2251 // emit go.mod 2252 verb(1, "opening go.mod") 2253 fn := s.OutDir + "/go.mod" 2254 outf, err := os.OpenFile(fn, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) 2255 if err != nil { 2256 log.Fatal(err) 2257 } 2258 outf.WriteString(fmt.Sprintf("module %s\n\ngo 1.17\n", s.PkgPath)) 2259 outf.Close() 2260 2261 verb(1, "closing files") 2262 mainoutfile.Close() 2263 2264 if s.errs == 0 && s.RunGoImports { 2265 runImports(allfiles) 2266 } 2267 2268 return s.errs 2269 }