--- /dev/null
+// Copyright 2022 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 rand_test
+
+import (
+ . "math/rand"
+ "testing"
+)
+
+// This test is first, in its own file with an alphabetically early name,
+// to try to make sure that it runs early. It has the best chance of
+// detecting deterministic seeding if it's the first test that runs.
+
+func TestAuto(t *testing.T) {
+ // Pull out 10 int64s from the global source
+ // and then check that they don't appear in that
+ // order in the deterministic Seed(1) result.
+ var out []int64
+ for i := 0; i < 10; i++ {
+ out = append(out, Int63())
+ }
+
+ // Look for out in Seed(1)'s output.
+ // Strictly speaking, we should look for them in order,
+ // but this is good enough and not significantly more
+ // likely to have a false positive.
+ Seed(1)
+ found := 0
+ for i := 0; i < 1000; i++ {
+ x := Int63()
+ if x == out[found] {
+ found++
+ if found == len(out) {
+ t.Fatalf("found unseeded output in Seed(1) output")
+ }
+ }
+ }
+}
// Package rand implements pseudo-random number generators unsuitable for
// security-sensitive work.
//
-// Random numbers are generated by a Source. Top-level functions, such as
-// Float64 and Int, use a default shared Source that produces a deterministic
-// sequence of values each time a program is run. Use the Seed function to
-// initialize the default Source if different behavior is required for each run.
-// The default Source is safe for concurrent use by multiple goroutines, but
-// Sources created by NewSource are not.
+// Random numbers are generated by a [Source], usually wrapped in a [Rand].
+// Both types should be used by a single goroutine at a time: sharing among
+// multiple goroutines requires some kind of synchronization.
+//
+// Top-level functions, such as [Float64] and [Int],
+// are safe for concurrent use by multiple goroutines.
//
// This package's outputs might be easily predictable regardless of how it's
// seeded. For random numbers suitable for security-sensitive work, see the
// crypto/rand package.
package rand
-import "sync"
+import (
+ "internal/godebug"
+ "sync"
+ _ "unsafe" // for go:linkname
+)
// A Source represents a source of uniformly-distributed
// pseudo-random int64 values in the range [0, 1<<63).
+//
+// A Source is not safe for concurrent use by multiple goroutines.
type Source interface {
Int63() int64
Seed(seed int64)
var globalRand = New(new(lockedSource))
// Seed uses the provided seed value to initialize the default Source to a
-// deterministic state. If Seed is not called, the generator behaves as
-// if seeded by Seed(1). Seed values that have the same remainder when
+// deterministic state. Seed values that have the same remainder when
// divided by 2³¹-1 generate the same pseudo-random sequence.
// Seed, unlike the Rand.Seed method, is safe for concurrent use.
+//
+// If Seed is not called, the generator is seeded randomly at program startup.
+//
+// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup.
+// To force the old behavior, call Seed(1) at program startup.
+// Alternately, set GODEBUG=randautoseed=0 in the environment
+// before making any calls to functions in this package.
+//
+// Note: Programs that call Seed and then expect a specific sequence
+// of results from the global random source (using functions such as Int)
+// can be broken when a dependency changes how much it consumes
+// from the global random source. To avoid such breakages, programs
+// that need a specific result sequence should use NewRand(NewSource(seed))
+// to obtain a random generator that other packages cannot access.
func Seed(seed int64) { globalRand.Seed(seed) }
// Int63 returns a non-negative pseudo-random 63-bit integer as an int64
s *rngSource // nil if not yet allocated
}
+//go:linkname fastrand64
+func fastrand64() uint64
+
// source returns r.s, allocating and seeding it if needed.
// The caller must have locked r.
func (r *lockedSource) source() *rngSource {
if r.s == nil {
- r.s = newSource(1)
+ var seed int64
+ if godebug.Get("randautoseed") == "0" {
+ seed = 1
+ } else {
+ seed = int64(fastrand64())
+ }
+ r.s = newSource(seed)
}
return r.s
}