mirror of
https://github.com/golang/go
synced 2024-11-15 03:00:36 -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
|
return
|
||||||
}
|
}
|
||||||
for i := range hashkey {
|
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"
|
"fmt"
|
||||||
"internal/abi"
|
"internal/abi"
|
||||||
"internal/goarch"
|
"internal/goarch"
|
||||||
|
"internal/testenv"
|
||||||
"math"
|
"math"
|
||||||
|
"os"
|
||||||
"reflect"
|
"reflect"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sort"
|
"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