Skip to content

Commit c29444e

Browse files
committed
math/rand, math/rand/v2: use ChaCha8 for global rand
Move ChaCha8 code into internal/chacha8rand and use it to implement runtime.rand, which is used for the unseeded global source for both math/rand and math/rand/v2. This also affects the calculation of the start point for iteration over very very large maps (when the 32-bit fastrand is not big enough). The benefit is that misuse of the global random number generators in math/rand and math/rand/v2 in contexts where non-predictable randomness is important for security reasons is no longer a security problem, removing a common mistake among programmers who are unaware of the different kinds of randomness. The cost is an extra 304 bytes per thread stored in the m struct plus 2-3ns more per random uint64 due to the more sophisticated algorithm. Using PCG looks like it would cost about the same, although I haven't benchmarked that. Before this, the math/rand and math/rand/v2 global generator was wyrand (https://github.com/wangyi-fudan/wyhash). For math/rand, using wyrand instead of the Mitchell/Reeds/Thompson ALFG was justifiable, since the latter was not any better. But for math/rand/v2, the global generator really should be at least as good as one of the well-studied, specific algorithms provided directly by the package, and it's not. (Wyrand is still reasonable for scheduling and cache decisions.) Good randomness does have a cost: about twice wyrand. Also rationalize the various runtime rand references. goos: linux goarch: amd64 pkg: math/rand/v2 cpu: AMD Ryzen 9 7950X 16-Core Processor │ bbb48afeb7.amd64 │ 5cf807d1ea.amd64 │ │ sec/op │ sec/op vs base │ ChaCha8-32 1.862n ± 2% 1.861n ± 2% ~ (p=0.825 n=20) PCG_DXSM-32 1.471n ± 1% 1.460n ± 2% ~ (p=0.153 n=20) SourceUint64-32 1.636n ± 2% 1.582n ± 1% -3.30% (p=0.000 n=20) GlobalInt64-32 2.087n ± 1% 3.663n ± 1% +75.54% (p=0.000 n=20) GlobalInt64Parallel-32 0.1042n ± 1% 0.2026n ± 1% +94.48% (p=0.000 n=20) GlobalUint64-32 2.263n ± 2% 3.724n ± 1% +64.57% (p=0.000 n=20) GlobalUint64Parallel-32 0.1019n ± 1% 0.1973n ± 1% +93.67% (p=0.000 n=20) Int64-32 1.771n ± 1% 1.774n ± 1% ~ (p=0.449 n=20) Uint64-32 1.863n ± 2% 1.866n ± 1% ~ (p=0.364 n=20) GlobalIntN1000-32 3.134n ± 3% 4.730n ± 2% +50.95% (p=0.000 n=20) IntN1000-32 2.489n ± 1% 2.489n ± 1% ~ (p=0.683 n=20) Int64N1000-32 2.521n ± 1% 2.516n ± 1% ~ (p=0.394 n=20) Int64N1e8-32 2.479n ± 1% 2.478n ± 2% ~ (p=0.743 n=20) Int64N1e9-32 2.530n ± 2% 2.514n ± 2% ~ (p=0.193 n=20) Int64N2e9-32 2.501n ± 1% 2.494n ± 1% ~ (p=0.616 n=20) Int64N1e18-32 3.227n ± 1% 3.205n ± 1% ~ (p=0.101 n=20) Int64N2e18-32 3.647n ± 1% 3.599n ± 1% ~ (p=0.019 n=20) Int64N4e18-32 5.135n ± 1% 5.069n ± 2% ~ (p=0.034 n=20) Int32N1000-32 2.657n ± 1% 2.637n ± 1% ~ (p=0.180 n=20) Int32N1e8-32 2.636n ± 1% 2.636n ± 1% ~ (p=0.763 n=20) Int32N1e9-32 2.660n ± 2% 2.638n ± 1% ~ (p=0.358 n=20) Int32N2e9-32 2.662n ± 2% 2.618n ± 2% ~ (p=0.064 n=20) Float32-32 2.272n ± 2% 2.239n ± 2% ~ (p=0.194 n=20) Float64-32 2.272n ± 1% 2.286n ± 2% ~ (p=0.763 n=20) ExpFloat64-32 3.762n ± 1% 3.744n ± 1% ~ (p=0.171 n=20) NormFloat64-32 3.706n ± 1% 3.655n ± 2% ~ (p=0.066 n=20) Perm3-32 32.93n ± 3% 34.62n ± 1% +5.13% (p=0.000 n=20) Perm30-32 202.9n ± 1% 204.0n ± 1% ~ (p=0.482 n=20) Perm30ViaShuffle-32 115.0n ± 1% 114.9n ± 1% ~ (p=0.358 n=20) ShuffleOverhead-32 112.8n ± 1% 112.7n ± 1% ~ (p=0.692 n=20) Concurrent-32 2.107n ± 0% 3.725n ± 1% +76.75% (p=0.000 n=20) goos: darwin goarch: arm64 pkg: math/rand/v2 │ bbb48afeb7.arm64 │ 5cf807d1ea.arm64 │ │ sec/op │ sec/op vs base │ ChaCha8-8 2.480n ± 0% 2.429n ± 0% -2.04% (p=0.000 n=20) PCG_DXSM-8 2.531n ± 0% 2.530n ± 0% ~ (p=0.877 n=20) SourceUint64-8 2.534n ± 0% 2.533n ± 0% ~ (p=0.732 n=20) GlobalInt64-8 2.172n ± 1% 4.794n ± 0% +120.67% (p=0.000 n=20) GlobalInt64Parallel-8 0.4320n ± 0% 0.9605n ± 0% +122.32% (p=0.000 n=20) GlobalUint64-8 2.182n ± 0% 4.770n ± 0% +118.58% (p=0.000 n=20) GlobalUint64Parallel-8 0.4307n ± 0% 0.9583n ± 0% +122.51% (p=0.000 n=20) Int64-8 4.107n ± 0% 4.104n ± 0% ~ (p=0.416 n=20) Uint64-8 4.080n ± 0% 4.080n ± 0% ~ (p=0.052 n=20) GlobalIntN1000-8 2.814n ± 2% 5.643n ± 0% +100.50% (p=0.000 n=20) IntN1000-8 4.141n ± 0% 4.139n ± 0% ~ (p=0.140 n=20) Int64N1000-8 4.140n ± 0% 4.140n ± 0% ~ (p=0.313 n=20) Int64N1e8-8 4.140n ± 0% 4.139n ± 0% ~ (p=0.103 n=20) Int64N1e9-8 4.139n ± 0% 4.140n ± 0% ~ (p=0.761 n=20) Int64N2e9-8 4.140n ± 0% 4.140n ± 0% ~ (p=0.636 n=20) Int64N1e18-8 5.266n ± 0% 5.326n ± 1% +1.14% (p=0.001 n=20) Int64N2e18-8 6.052n ± 0% 6.167n ± 0% +1.90% (p=0.000 n=20) Int64N4e18-8 8.826n ± 0% 9.051n ± 0% +2.55% (p=0.000 n=20) Int32N1000-8 4.127n ± 0% 4.132n ± 0% +0.12% (p=0.000 n=20) Int32N1e8-8 4.126n ± 0% 4.131n ± 0% +0.12% (p=0.000 n=20) Int32N1e9-8 4.127n ± 0% 4.132n ± 0% +0.12% (p=0.000 n=20) Int32N2e9-8 4.132n ± 0% 4.131n ± 0% ~ (p=0.017 n=20) Float32-8 4.109n ± 0% 4.105n ± 0% ~ (p=0.379 n=20) Float64-8 4.107n ± 0% 4.106n ± 0% ~ (p=0.867 n=20) ExpFloat64-8 5.339n ± 0% 5.383n ± 0% +0.82% (p=0.000 n=20) NormFloat64-8 5.735n ± 0% 5.737n ± 1% ~ (p=0.856 n=20) Perm3-8 26.65n ± 0% 26.80n ± 1% +0.58% (p=0.000 n=20) Perm30-8 194.8n ± 1% 197.0n ± 0% +1.18% (p=0.000 n=20) Perm30ViaShuffle-8 156.6n ± 0% 157.6n ± 1% +0.61% (p=0.000 n=20) ShuffleOverhead-8 124.9n ± 0% 125.5n ± 0% +0.52% (p=0.000 n=20) Concurrent-8 2.434n ± 3% 5.066n ± 0% +108.09% (p=0.000 n=20) goos: linux goarch: 386 pkg: math/rand/v2 cpu: AMD Ryzen 9 7950X 16-Core Processor │ bbb48afeb7.386 │ 5cf807d1ea.386 │ │ sec/op │ sec/op vs base │ ChaCha8-32 11.295n ± 1% 4.748n ± 2% -57.96% (p=0.000 n=20) PCG_DXSM-32 7.693n ± 1% 7.738n ± 2% ~ (p=0.542 n=20) SourceUint64-32 7.658n ± 2% 7.622n ± 2% ~ (p=0.344 n=20) GlobalInt64-32 3.473n ± 2% 7.526n ± 2% +116.73% (p=0.000 n=20) GlobalInt64Parallel-32 0.3198n ± 0% 0.5444n ± 0% +70.22% (p=0.000 n=20) GlobalUint64-32 3.612n ± 0% 7.575n ± 1% +109.69% (p=0.000 n=20) GlobalUint64Parallel-32 0.3168n ± 0% 0.5403n ± 0% +70.51% (p=0.000 n=20) Int64-32 7.673n ± 2% 7.789n ± 1% ~ (p=0.122 n=20) Uint64-32 7.773n ± 1% 7.827n ± 2% ~ (p=0.920 n=20) GlobalIntN1000-32 6.268n ± 1% 9.581n ± 1% +52.87% (p=0.000 n=20) IntN1000-32 10.33n ± 2% 10.45n ± 1% ~ (p=0.233 n=20) Int64N1000-32 10.98n ± 2% 11.01n ± 1% ~ (p=0.401 n=20) Int64N1e8-32 11.19n ± 2% 10.97n ± 1% ~ (p=0.033 n=20) Int64N1e9-32 11.06n ± 1% 11.08n ± 1% ~ (p=0.498 n=20) Int64N2e9-32 11.10n ± 1% 11.01n ± 2% ~ (p=0.995 n=20) Int64N1e18-32 15.23n ± 2% 15.04n ± 1% ~ (p=0.973 n=20) Int64N2e18-32 15.89n ± 1% 15.85n ± 1% ~ (p=0.409 n=20) Int64N4e18-32 18.96n ± 2% 19.34n ± 2% ~ (p=0.048 n=20) Int32N1000-32 10.46n ± 2% 10.44n ± 2% ~ (p=0.480 n=20) Int32N1e8-32 10.46n ± 2% 10.49n ± 2% ~ (p=0.951 n=20) Int32N1e9-32 10.28n ± 2% 10.26n ± 1% ~ (p=0.431 n=20) Int32N2e9-32 10.50n ± 2% 10.44n ± 2% ~ (p=0.249 n=20) Float32-32 13.80n ± 2% 13.80n ± 2% ~ (p=0.751 n=20) Float64-32 23.55n ± 2% 23.87n ± 0% ~ (p=0.408 n=20) ExpFloat64-32 15.36n ± 1% 15.29n ± 2% ~ (p=0.316 n=20) NormFloat64-32 13.57n ± 1% 13.79n ± 1% +1.66% (p=0.005 n=20) Perm3-32 45.70n ± 2% 46.99n ± 2% +2.81% (p=0.001 n=20) Perm30-32 399.0n ± 1% 403.8n ± 1% +1.19% (p=0.006 n=20) Perm30ViaShuffle-32 349.0n ± 1% 350.4n ± 1% ~ (p=0.909 n=20) ShuffleOverhead-32 322.3n ± 1% 323.8n ± 1% ~ (p=0.410 n=20) Concurrent-32 3.331n ± 1% 7.312n ± 1% +119.50% (p=0.000 n=20) For #61716. Change-Id: Ibdddeed85c34d9ae397289dc899e04d4845f9ed2 Reviewed-on: https://go-review.googlesource.com/c/go/+/516860 Reviewed-by: Michael Pratt <mpratt@google.com> Reviewed-by: Filippo Valsorda <filippo@golang.org> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
1 parent d924349 commit c29444e

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

66 files changed

+415
-305
lines changed

src/cmd/compile/internal/test/inl_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,6 @@ func TestIntendedInlining(t *testing.T) {
4444
"chanbuf",
4545
"evacuated",
4646
"fastlog2",
47-
"fastrand",
4847
"float64bits",
4948
"funcspdelta",
5049
"getm",
@@ -54,6 +53,7 @@ func TestIntendedInlining(t *testing.T) {
5453
"nextslicecap",
5554
"noescape",
5655
"pcvalueCacheKey",
56+
"rand32",
5757
"readUnaligned32",
5858
"readUnaligned64",
5959
"releasem",

src/cmd/compile/internal/typecheck/_builtin/runtime.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ func panicrangeexit()
122122
// defer in range over func
123123
func deferrangefunc() interface{}
124124

125-
func fastrand() uint32
125+
func rand32() uint32
126126

127127
// *byte is really *runtime.Type
128128
func makemap64(mapType *byte, hint int64, mapbuf *any) (hmap map[any]any)

src/cmd/compile/internal/typecheck/builtin.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/compile/internal/walk/builtin.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -358,8 +358,8 @@ func walkMakeMap(n *ir.MakeExpr, init *ir.Nodes) ir.Node {
358358
if n.Esc() == ir.EscNone {
359359
// Only need to initialize h.hash0 since
360360
// hmap h has been allocated on the stack already.
361-
// h.hash0 = fastrand()
362-
rand := mkcall("fastrand", types.Types[types.TUINT32], init)
361+
// h.hash0 = rand32()
362+
rand := mkcall("rand32", types.Types[types.TUINT32], init)
363363
hashsym := hmapType.Field(4).Sym // hmap.hash0 see reflect.go:hmap
364364
appendWalkStmt(init, ir.NewAssignStmt(base.Pos, ir.NewSelectorExpr(base.Pos, ir.ODOT, h, hashsym), rand))
365365
return typecheck.ConvNop(h, t)

src/cmd/internal/goobj/builtinlist.go

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/cmd/internal/objabi/pkgspecial.go

+2
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ var runtimePkgs = []string{
5050

5151
"internal/abi",
5252
"internal/bytealg",
53+
"internal/chacha8rand",
5354
"internal/coverage/rtcov",
5455
"internal/cpu",
5556
"internal/goarch",
@@ -79,6 +80,7 @@ var allowAsmABIPkgs = []string{
7980
"reflect",
8081
"syscall",
8182
"internal/bytealg",
83+
"internal/chacha8rand",
8284
"runtime/internal/syscall",
8385
"runtime/internal/startlinetest",
8486
}

src/cmd/link/internal/ld/data.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -56,10 +56,11 @@ import (
5656
func isRuntimeDepPkg(pkg string) bool {
5757
switch pkg {
5858
case "runtime",
59-
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname
60-
"internal/abi", // used by reflectcall (and maybe more)
61-
"internal/bytealg", // for IndexByte
62-
"internal/cpu": // for cpu features
59+
"sync/atomic", // runtime may call to sync/atomic, due to go:linkname
60+
"internal/abi", // used by reflectcall (and maybe more)
61+
"internal/bytealg", // for IndexByte
62+
"internal/chacha8rand", // for rand
63+
"internal/cpu": // for cpu features
6364
return true
6465
}
6566
return strings.HasPrefix(pkg, "runtime/internal/") && !strings.HasSuffix(pkg, "_test")

src/hash/maphash/maphash_runtime.go

+3-3
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ import (
1010
"unsafe"
1111
)
1212

13-
//go:linkname runtime_fastrand64 runtime.fastrand64
14-
func runtime_fastrand64() uint64
13+
//go:linkname runtime_rand runtime.rand
14+
func runtime_rand() uint64
1515

1616
//go:linkname runtime_memhash runtime.memhash
1717
//go:noescape
@@ -39,5 +39,5 @@ func rthashString(s string, state uint64) uint64 {
3939
}
4040

4141
func randUint64() uint64 {
42-
return runtime_fastrand64()
42+
return runtime_rand()
4343
}

src/internal/chacha8rand/chacha8.go

+19
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,25 @@ func (s *State) Refill() {
9393
}
9494
}
9595

96+
// Reseed reseeds the state with new random values.
97+
// After a call to Reseed, any previously returned random values
98+
// have been erased from the memory of the state and cannot be
99+
// recovered.
100+
func (s *State) Reseed() {
101+
var seed [4]uint64
102+
for i := range seed {
103+
for {
104+
x, ok := s.Next()
105+
if ok {
106+
seed[i] = x
107+
break
108+
}
109+
s.Refill()
110+
}
111+
}
112+
s.Init64(seed)
113+
}
114+
96115
// Marshal marshals the state into a byte slice.
97116
// Marshal and Unmarshal are functions, not methods,
98117
// so that they will not be linked into the runtime

src/internal/chacha8rand/chacha8_amd64.s

+1-4
Original file line numberDiff line numberDiff line change
@@ -52,13 +52,10 @@
5252
// block runs 4 ChaCha8 block transformations in the four stripes of the X registers.
5353

5454
// func block(seed *[8]uint32, blocks *[16][4]uint32, counter uint32)
55-
TEXT ·block(SB), NOSPLIT, $16
55+
TEXT ·block<ABIInternal>(SB), NOSPLIT, $16
5656
// seed in AX
5757
// blocks in BX
5858
// counter in CX
59-
MOVQ seed+0(FP), AX
60-
MOVQ blocks+8(FP), BX
61-
MOVL counter+16(FP), CX
6259

6360
// Load initial constants into top row.
6461
REPL(0x61707865, X0)

src/internal/chacha8rand/chacha8_arm64.s

+2-4
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,10 @@
1616
// block runs 4 ChaCha8 block transformations in the four stripes of the V registers.
1717

1818
// func block(seed *[8]uint32, blocks *[4][16]uint32, counter uint32)
19-
TEXT ·block(SB), NOSPLIT, $16
19+
TEXT ·block<ABIInternal>(SB), NOSPLIT, $16
2020
// seed in R0
2121
// blocks in R1
22-
MOVD seed+0(FP), R0
23-
MOVD blocks+8(FP), R1
24-
MOVW counter+16(FP), R2
22+
// counter in R2
2523

2624
// Load initial constants into top row.
2725
MOVD $·chachaConst(SB), R10

src/internal/chacha8rand/export_test.go

+4
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,7 @@ package chacha8rand
66

77
var Block = block
88
var Block_generic = block_generic
9+
10+
func Seed(s *State) [4]uint64 {
11+
return s.seed
12+
}

src/internal/chacha8rand/rand_test.go

+10
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ func TestMarshal(t *testing.T) {
5353
}
5454
}
5555

56+
func TestReseed(t *testing.T) {
57+
var s State
58+
s.Init(seed)
59+
old := Seed(&s)
60+
s.Reseed()
61+
if Seed(&s) == old {
62+
t.Errorf("Reseed did not change seed")
63+
}
64+
}
65+
5666
func BenchmarkBlock(b *testing.B) {
5767
var seed [4]uint64
5868
var blocks [32]uint64

src/internal/coverage/pkid.go

+1
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ var rtPkgs = [...]string{
4949
"internal/goarch",
5050
"runtime/internal/atomic",
5151
"internal/goos",
52+
"internal/chacha8rand",
5253
"runtime/internal/sys",
5354
"internal/abi",
5455
"runtime/internal/math",

src/math/rand/rand.go

+15-15
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ func (r *Rand) Read(p []byte) (n int, err error) {
273273
switch src := r.src.(type) {
274274
case *lockedSource:
275275
return src.read(p, &r.readVal, &r.readPos)
276-
case *fastSource:
276+
case *runtimeSource:
277277
return src.read(p, &r.readVal, &r.readPos)
278278
}
279279
return read(p, r.src, &r.readVal, &r.readPos)
@@ -328,8 +328,8 @@ func globalRand() *Rand {
328328
r.Seed(1)
329329
} else {
330330
r = &Rand{
331-
src: &fastSource{},
332-
s64: &fastSource{},
331+
src: &runtimeSource{},
332+
s64: &runtimeSource{},
333333
}
334334
}
335335

@@ -346,29 +346,29 @@ func globalRand() *Rand {
346346
return r
347347
}
348348

349-
//go:linkname fastrand64
350-
func fastrand64() uint64
349+
//go:linkname runtime_rand runtime.rand
350+
func runtime_rand() uint64
351351

352-
// fastSource is an implementation of Source64 that uses the runtime
352+
// runtimeSource is an implementation of Source64 that uses the runtime
353353
// fastrand functions.
354-
type fastSource struct {
354+
type runtimeSource struct {
355355
// The mutex is used to avoid race conditions in Read.
356356
mu sync.Mutex
357357
}
358358

359-
func (*fastSource) Int63() int64 {
360-
return int64(fastrand64() & rngMask)
359+
func (*runtimeSource) Int63() int64 {
360+
return int64(runtime_rand() & rngMask)
361361
}
362362

363-
func (*fastSource) Seed(int64) {
364-
panic("internal error: call to fastSource.Seed")
363+
func (*runtimeSource) Seed(int64) {
364+
panic("internal error: call to runtimeSource.Seed")
365365
}
366366

367-
func (*fastSource) Uint64() uint64 {
368-
return fastrand64()
367+
func (*runtimeSource) Uint64() uint64 {
368+
return runtime_rand()
369369
}
370370

371-
func (fs *fastSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
371+
func (fs *runtimeSource) read(p []byte, readVal *int64, readPos *int8) (n int, err error) {
372372
fs.mu.Lock()
373373
n, err = read(p, fs, readVal, readPos)
374374
fs.mu.Unlock()
@@ -405,7 +405,7 @@ func Seed(seed int64) {
405405
// Otherwise either
406406
// 1) orig == nil, which is the normal case when Seed is the first
407407
// top-level function to be called, or
408-
// 2) orig is already a fastSource, in which case we need to change
408+
// 2) orig is already a runtimeSource, in which case we need to change
409409
// to a lockedSource.
410410
// Either way we do the same thing.
411411

src/math/rand/v2/rand.go

+7-11
Original file line numberDiff line numberDiff line change
@@ -250,20 +250,16 @@ func (r *Rand) Shuffle(n int, swap func(i, j int)) {
250250

251251
// globalRand is the source of random numbers for the top-level
252252
// convenience functions.
253-
var globalRand = &Rand{src: &fastSource{}}
253+
var globalRand = &Rand{src: &runtimeSource{}}
254254

255-
//go:linkname fastrand64
256-
func fastrand64() uint64
255+
//go:linkname runtime_rand runtime.rand
256+
func runtime_rand() uint64
257257

258-
// fastSource is a Source that uses the runtime fastrand functions.
259-
type fastSource struct{}
258+
// runtimeSource is a Source that uses the runtime fastrand functions.
259+
type runtimeSource struct{}
260260

261-
func (*fastSource) Int64() int64 {
262-
return int64(fastrand64() << 1 >> 1)
263-
}
264-
265-
func (*fastSource) Uint64() uint64 {
266-
return fastrand64()
261+
func (*runtimeSource) Uint64() uint64 {
262+
return runtime_rand()
267263
}
268264

269265
// Int64 returns a non-negative pseudo-random 63-bit integer as an int64

src/net/dnsclient.go

+4-2
Original file line numberDiff line numberDiff line change
@@ -8,15 +8,17 @@ import (
88
"internal/bytealg"
99
"internal/itoa"
1010
"sort"
11+
_ "unsafe" // for go:linkname
1112

1213
"golang.org/x/net/dns/dnsmessage"
1314
)
1415

1516
// provided by runtime
16-
func fastrandu() uint
17+
//go:linkname runtime_rand runtime.rand
18+
func runtime_rand() uint64
1719

1820
func randInt() int {
19-
return int(fastrandu() >> 1) // clear sign bit
21+
return int(uint(runtime_rand()) >> 1) // clear sign bit
2022
}
2123

2224
func randIntn(n int) int {

src/os/tempfile.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,18 @@ import (
88
"errors"
99
"internal/bytealg"
1010
"internal/itoa"
11+
_ "unsafe" // for go:linkname
1112
)
1213

13-
// fastrand provided by runtime.
14+
// random number source provided by runtime.
1415
// We generate random temporary file names so that there's a good
1516
// chance the file doesn't exist yet - keeps the number of tries in
1617
// TempFile to a minimum.
17-
func fastrand() uint32
18+
//go:linkname runtime_rand runtime.rand
19+
func runtime_rand() uint64
1820

1921
func nextRandom() string {
20-
return itoa.Uitoa(uint(fastrand()))
22+
return itoa.Uitoa(uint(runtime_rand()))
2123
}
2224

2325
// CreateTemp creates a new temporary file in the directory dir,

src/runtime/alg.go

+9-8
Original file line numberDiff line numberDiff line change
@@ -66,7 +66,7 @@ func f32hash(p unsafe.Pointer, h uintptr) uintptr {
6666
case f == 0:
6767
return c1 * (c0 ^ h) // +0, -0
6868
case f != f:
69-
return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
69+
return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN
7070
default:
7171
return memhash(p, h, 4)
7272
}
@@ -78,7 +78,7 @@ func f64hash(p unsafe.Pointer, h uintptr) uintptr {
7878
case f == 0:
7979
return c1 * (c0 ^ h) // +0, -0
8080
case f != f:
81-
return c1 * (c0 ^ h ^ uintptr(fastrand())) // any kind of NaN
81+
return c1 * (c0 ^ h ^ uintptr(rand())) // any kind of NaN
8282
default:
8383
return memhash(p, h, 8)
8484
}
@@ -390,17 +390,18 @@ func alginit() {
390390
initAlgAES()
391391
return
392392
}
393-
getRandomData((*[len(hashkey) * goarch.PtrSize]byte)(unsafe.Pointer(&hashkey))[:])
394-
hashkey[0] |= 1 // make sure these numbers are odd
395-
hashkey[1] |= 1
396-
hashkey[2] |= 1
397-
hashkey[3] |= 1
393+
for i := range hashkey {
394+
hashkey[i] = uintptr(rand()) | 1 // make sure these numbers are odd
395+
}
398396
}
399397

400398
func initAlgAES() {
401399
useAeshash = true
402400
// Initialize with random data so hash collisions will be hard to engineer.
403-
getRandomData(aeskeysched[:])
401+
key := (*[hashRandomBytes / 8]uint64)(unsafe.Pointer(&aeskeysched))
402+
for i := range key {
403+
key[i] = bootstrapRand()
404+
}
404405
}
405406

406407
// Note: These routines perform the read with a native endianness.

src/runtime/export_test.go

+5-3
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ var Exitsyscall = exitsyscall
3131
var LockedOSThread = lockedOSThread
3232
var Xadduintptr = atomic.Xadduintptr
3333

34+
var ReadRandomFailed = &readRandomFailed
35+
3436
var Fastlog2 = fastlog2
3537

3638
var Atoi = atoi
@@ -398,9 +400,9 @@ func CountPagesInUse() (pagesInUse, counted uintptr) {
398400
return
399401
}
400402

401-
func Fastrand() uint32 { return fastrand() }
402-
func Fastrand64() uint64 { return fastrand64() }
403-
func Fastrandn(n uint32) uint32 { return fastrandn(n) }
403+
func Fastrand() uint32 { return uint32(rand()) }
404+
func Fastrand64() uint64 { return rand() }
405+
func Fastrandn(n uint32) uint32 { return randn(n) }
404406

405407
type ProfBuf profBuf
406408

0 commit comments

Comments
 (0)