|
5 | 5 | // Package rand implements pseudo-random number generators unsuitable for
|
6 | 6 | // security-sensitive work.
|
7 | 7 | //
|
8 |
| -// Random numbers are generated by a Source. Top-level functions, such as |
9 |
| -// Float64 and Int, use a default shared Source that produces a deterministic |
10 |
| -// sequence of values each time a program is run. Use the Seed function to |
11 |
| -// initialize the default Source if different behavior is required for each run. |
12 |
| -// The default Source is safe for concurrent use by multiple goroutines, but |
13 |
| -// Sources created by NewSource are not. |
| 8 | +// Random numbers are generated by a [Source], usually wrapped in a [Rand]. |
| 9 | +// Both types should be used by a single goroutine at a time: sharing among |
| 10 | +// multiple goroutines requires some kind of synchronization. |
| 11 | +// |
| 12 | +// Top-level functions, such as [Float64] and [Int], |
| 13 | +// are safe for concurrent use by multiple goroutines. |
14 | 14 | //
|
15 | 15 | // This package's outputs might be easily predictable regardless of how it's
|
16 | 16 | // seeded. For random numbers suitable for security-sensitive work, see the
|
17 | 17 | // crypto/rand package.
|
18 | 18 | package rand
|
19 | 19 |
|
20 |
| -import "sync" |
| 20 | +import ( |
| 21 | + "internal/godebug" |
| 22 | + "sync" |
| 23 | + _ "unsafe" // for go:linkname |
| 24 | +) |
21 | 25 |
|
22 | 26 | // A Source represents a source of uniformly-distributed
|
23 | 27 | // pseudo-random int64 values in the range [0, 1<<63).
|
| 28 | +// |
| 29 | +// A Source is not safe for concurrent use by multiple goroutines. |
24 | 30 | type Source interface {
|
25 | 31 | Int63() int64
|
26 | 32 | Seed(seed int64)
|
@@ -298,10 +304,23 @@ func read(p []byte, src Source, readVal *int64, readPos *int8) (n int, err error
|
298 | 304 | var globalRand = New(new(lockedSource))
|
299 | 305 |
|
300 | 306 | // Seed uses the provided seed value to initialize the default Source to a
|
301 |
| -// deterministic state. If Seed is not called, the generator behaves as |
302 |
| -// if seeded by Seed(1). Seed values that have the same remainder when |
| 307 | +// deterministic state. Seed values that have the same remainder when |
303 | 308 | // divided by 2³¹-1 generate the same pseudo-random sequence.
|
304 | 309 | // Seed, unlike the Rand.Seed method, is safe for concurrent use.
|
| 310 | +// |
| 311 | +// If Seed is not called, the generator is seeded randomly at program startup. |
| 312 | +// |
| 313 | +// Prior to Go 1.20, the generator was seeded like Seed(1) at program startup. |
| 314 | +// To force the old behavior, call Seed(1) at program startup. |
| 315 | +// Alternately, set GODEBUG=randautoseed=0 in the environment |
| 316 | +// before making any calls to functions in this package. |
| 317 | +// |
| 318 | +// Note: Programs that call Seed and then expect a specific sequence |
| 319 | +// of results from the global random source (using functions such as Int) |
| 320 | +// can be broken when a dependency changes how much it consumes |
| 321 | +// from the global random source. To avoid such breakages, programs |
| 322 | +// that need a specific result sequence should use NewRand(NewSource(seed)) |
| 323 | +// to obtain a random generator that other packages cannot access. |
305 | 324 | func Seed(seed int64) { globalRand.Seed(seed) }
|
306 | 325 |
|
307 | 326 | // Int63 returns a non-negative pseudo-random 63-bit integer as an int64
|
@@ -384,11 +403,20 @@ type lockedSource struct {
|
384 | 403 | s *rngSource // nil if not yet allocated
|
385 | 404 | }
|
386 | 405 |
|
| 406 | +//go:linkname fastrand64 |
| 407 | +func fastrand64() uint64 |
| 408 | + |
387 | 409 | // source returns r.s, allocating and seeding it if needed.
|
388 | 410 | // The caller must have locked r.
|
389 | 411 | func (r *lockedSource) source() *rngSource {
|
390 | 412 | if r.s == nil {
|
391 |
| - r.s = newSource(1) |
| 413 | + var seed int64 |
| 414 | + if godebug.Get("randautoseed") == "0" { |
| 415 | + seed = 1 |
| 416 | + } else { |
| 417 | + seed = int64(fastrand64()) |
| 418 | + } |
| 419 | + r.s = newSource(seed) |
392 | 420 | }
|
393 | 421 | return r.s
|
394 | 422 | }
|
|
0 commit comments