| // 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() {} |