When clearing a map, reinitialize the hash seed with random data. This
makes it more difficult for attackers to trigger pathological
performance via repeated hash collisions.
The extra reinitialization causes no statistically significant slowdown:
name old time/op new time/op delta
GoMapClear/Reflexive/1-12 18.3ns ± 0% 20.0ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/Reflexive/10-12 18.2ns ± 0% 19.8ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/Reflexive/100-12 44.6ns ± 0% 46.1ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/Reflexive/1000-12 592ns ± 0% 592ns ± 0% ~ (all samples are equal)
GoMapClear/Reflexive/10000-12 3.88µs ± 0% 3.88µs ± 0% ~ (p=1.000 n=1+1)
GoMapClear/NonReflexive/1-12 62.7ns ± 0% 63.9ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/NonReflexive/10-12 75.0ns ± 0% 76.1ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/NonReflexive/100-12 203ns ± 0% 206ns ± 0% ~ (p=1.000 n=1+1)
GoMapClear/NonReflexive/1000-12 2.33µs ± 0% 2.33µs ± 0% ~ (all samples are equal)
GoMapClear/NonReflexive/10000-12 18.1µs ± 0% 18.1µs ± 0% ~ (p=1.000 n=1+1)
Fixes #25237
Change-Id: I629a79dd7c562ba18bd94159673c3b9b653da643
Reviewed-on: https://go-review.googlesource.com/c/go/+/253020
Reviewed-by: Keith Randall <khr@golang.org>
h.noverflow = 0
h.count = 0
+ // Reset the hash seed to make it more difficult for attackers to
+ // repeatedly trigger hash collisions. See issue 25237.
+ h.hash0 = fastrand()
+
// Keep the mapextra allocation but clear any extra information.
if h.extra != nil {
*h.extra = mapextra{}