mirror of
https://github.com/golang/go
synced 2024-11-15 00:20:30 -07:00
runtime: use bootstrapRand to initialize hashkey
The seed for rand is not initialized until after alginit. Before initialization, rand returns a deterministic sequence, making hashkey deterministic across processes. Switch to bootstrapRand, like other early rand calls, such as initialization of aeskeysched. Fixes #66885. Change-Id: I5023a9161232b49fda2ebd1d5f9338bbdd17b1fe Reviewed-on: https://go-review.googlesource.com/c/go/+/580136 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@golang.org> Reviewed-by: Keith Randall <khr@google.com>
This commit is contained in:
parent
1a0b86375f
commit
1a3682b4c1
@ -391,7 +391,7 @@ func alginit() {
|
||||
return
|
||||
}
|
||||
for i := range hashkey {
|
||||
hashkey[i] = uintptr(rand()) | 1 // make sure these numbers are odd
|
||||
hashkey[i] = uintptr(bootstrapRand()) | 1 // make sure these numbers are odd
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,9 @@ import (
|
||||
"fmt"
|
||||
"internal/abi"
|
||||
"internal/goarch"
|
||||
"internal/testenv"
|
||||
"math"
|
||||
"os"
|
||||
"reflect"
|
||||
"runtime"
|
||||
"sort"
|
||||
@ -1464,3 +1466,81 @@ func TestMapValues(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func computeHash() uintptr {
|
||||
var v struct{}
|
||||
return runtime.MemHash(unsafe.Pointer(&v), 0, unsafe.Sizeof(v))
|
||||
}
|
||||
|
||||
func subprocessHash(t *testing.T, env string) uintptr {
|
||||
t.Helper()
|
||||
|
||||
cmd := testenv.CleanCmdEnv(testenv.Command(t, os.Args[0], "-test.run=^TestMemHashGlobalSeed$"))
|
||||
cmd.Env = append(cmd.Env, "GO_TEST_SUBPROCESS_HASH=1")
|
||||
if env != "" {
|
||||
cmd.Env = append(cmd.Env, env)
|
||||
}
|
||||
|
||||
out, err := cmd.Output()
|
||||
if err != nil {
|
||||
t.Fatalf("cmd.Output got err %v want nil", err)
|
||||
}
|
||||
|
||||
s := strings.TrimSpace(string(out))
|
||||
h, err := strconv.ParseUint(s, 10, 64)
|
||||
if err != nil {
|
||||
t.Fatalf("Parse output %q got err %v want nil", s, err)
|
||||
}
|
||||
return uintptr(h)
|
||||
}
|
||||
|
||||
// memhash has unique per-process seeds, so hashes should differ across
|
||||
// processes.
|
||||
//
|
||||
// Regression test for https://go.dev/issue/66885.
|
||||
func TestMemHashGlobalSeed(t *testing.T) {
|
||||
if os.Getenv("GO_TEST_SUBPROCESS_HASH") != "" {
|
||||
fmt.Println(computeHash())
|
||||
os.Exit(0)
|
||||
return
|
||||
}
|
||||
|
||||
testenv.MustHaveExec(t)
|
||||
|
||||
// aeshash and memhashFallback use separate per-process seeds, so test
|
||||
// both.
|
||||
t.Run("aes", func(t *testing.T) {
|
||||
if !*runtime.UseAeshash {
|
||||
t.Skip("No AES")
|
||||
}
|
||||
|
||||
h1 := subprocessHash(t, "")
|
||||
t.Logf("%d", h1)
|
||||
h2 := subprocessHash(t, "")
|
||||
t.Logf("%d", h2)
|
||||
h3 := subprocessHash(t, "")
|
||||
t.Logf("%d", h3)
|
||||
|
||||
if h1 == h2 && h2 == h3 {
|
||||
t.Errorf("got duplicate hash %d want unique", h1)
|
||||
}
|
||||
})
|
||||
|
||||
t.Run("noaes", func(t *testing.T) {
|
||||
env := ""
|
||||
if *runtime.UseAeshash {
|
||||
env = "GODEBUG=cpu.aes=off"
|
||||
}
|
||||
|
||||
h1 := subprocessHash(t, env)
|
||||
t.Logf("%d", h1)
|
||||
h2 := subprocessHash(t, env)
|
||||
t.Logf("%d", h2)
|
||||
h3 := subprocessHash(t, env)
|
||||
t.Logf("%d", h3)
|
||||
|
||||
if h1 == h2 && h2 == h3 {
|
||||
t.Errorf("got duplicate hash %d want unique", h1)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user