| // Copyright 2020 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| package fuzz | |
| import ( | |
| "math/bits" | |
| "os" | |
| "strconv" | |
| "strings" | |
| "sync/atomic" | |
| "time" | |
| ) | |
| type mutatorRand interface { | |
| uint32() uint32 | |
| intn(int) int | |
| uint32n(uint32) uint32 | |
| exp2() int | |
| bool() bool | |
| save(randState, randInc *uint64) | |
| restore(randState, randInc uint64) | |
| } | |
| // The functions in pcg implement a 32 bit PRNG with a 64 bit period: pcg xsh rr | |
| // 64 32. See https://www.pcg-random.org/ for more information. This | |
| // implementation is geared specifically towards the needs of fuzzing: Simple | |
| // creation and use, no reproducibility, no concurrency safety, just the | |
| // necessary methods, optimized for speed. | |
| var globalInc uint64 // PCG stream | |
| const multiplier uint64 = 6364136223846793005 | |
| // pcgRand is a PRNG. It should not be copied or shared. No Rand methods are | |
| // concurrency safe. | |
| type pcgRand struct { | |
| noCopy noCopy // help avoid mistakes: ask vet to ensure that we don't make a copy | |
| state uint64 | |
| inc uint64 | |
| } | |
| func godebugSeed() *int { | |
| debug := strings.Split(os.Getenv("GODEBUG"), ",") | |
| for _, f := range debug { | |
| if strings.HasPrefix(f, "fuzzseed=") { | |
| seed, err := strconv.Atoi(strings.TrimPrefix(f, "fuzzseed=")) | |
| if err != nil { | |
| panic("malformed fuzzseed") | |
| } | |
| return &seed | |
| } | |
| } | |
| return nil | |
| } | |
| // newPcgRand generates a new, seeded Rand, ready for use. | |
| func newPcgRand() *pcgRand { | |
| r := new(pcgRand) | |
| now := uint64(time.Now().UnixNano()) | |
| if seed := godebugSeed(); seed != nil { | |
| now = uint64(*seed) | |
| } | |
| inc := atomic.AddUint64(&globalInc, 1) | |
| r.state = now | |
| r.inc = (inc << 1) | 1 | |
| r.step() | |
| r.state += now | |
| r.step() | |
| return r | |
| } | |
| func (r *pcgRand) step() { | |
| r.state *= multiplier | |
| r.state += r.inc | |
| } | |
| func (r *pcgRand) save(randState, randInc *uint64) { | |
| *randState = r.state | |
| *randInc = r.inc | |
| } | |
| func (r *pcgRand) restore(randState, randInc uint64) { | |
| r.state = randState | |
| r.inc = randInc | |
| } | |
| // uint32 returns a pseudo-random uint32. | |
| func (r *pcgRand) uint32() uint32 { | |
| x := r.state | |
| r.step() | |
| return bits.RotateLeft32(uint32(((x>>18)^x)>>27), -int(x>>59)) | |
| } | |
| // intn returns a pseudo-random number in [0, n). | |
| // n must fit in a uint32. | |
| func (r *pcgRand) intn(n int) int { | |
| if int(uint32(n)) != n { | |
| panic("large Intn") | |
| } | |
| return int(r.uint32n(uint32(n))) | |
| } | |
| // uint32n returns a pseudo-random number in [0, n). | |
| // | |
| // For implementation details, see: | |
| // https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction | |
| // https://lemire.me/blog/2016/06/30/fast-random-shuffling | |
| func (r *pcgRand) uint32n(n uint32) uint32 { | |
| v := r.uint32() | |
| prod := uint64(v) * uint64(n) | |
| low := uint32(prod) | |
| if low < n { | |
| thresh := uint32(-int32(n)) % n | |
| for low < thresh { | |
| v = r.uint32() | |
| prod = uint64(v) * uint64(n) | |
| low = uint32(prod) | |
| } | |
| } | |
| return uint32(prod >> 32) | |
| } | |
| // exp2 generates n with probability 1/2^(n+1). | |
| func (r *pcgRand) exp2() int { | |
| return bits.TrailingZeros32(r.uint32()) | |
| } | |
| // bool generates a random bool. | |
| func (r *pcgRand) bool() bool { | |
| return r.uint32()&1 == 0 | |
| } | |
| // noCopy may be embedded into structs which must not be copied | |
| // after the first use. | |
| // | |
| // See https://golang.org/issues/8005#issuecomment-190753527 | |
| // for details. | |
| type noCopy struct{} | |
| // lock is a no-op used by -copylocks checker from `go vet`. | |
| func (*noCopy) lock() {} | |
| func (*noCopy) unlock() {} |