From 7f095617f26bac43d91425935432f16965c04873 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 2 Jul 2021 13:45:23 -0700 Subject: [PATCH] internal/deephash: 8 bits of output is not enough Running hex.Encode(b, b) is a bad idea. The first byte of input will overwrite the first two bytes of output. Subsequent bytes have no impact on the output. Not related to today's IPv6 bug, but...wh::ps. This caused us to spuriously ignore some wireguard config updates. Signed-off-by: Josh Bleecher Snyder --- internal/deephash/deephash.go | 8 ++++++-- internal/deephash/deephash_test.go | 11 +++++++++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/internal/deephash/deephash.go b/internal/deephash/deephash.go index e969e02b7..b33531873 100644 --- a/internal/deephash/deephash.go +++ b/internal/deephash/deephash.go @@ -24,8 +24,12 @@ func calcHash(v interface{}) string { printTo(b, v, scratch) b.Flush() scratch = h.Sum(scratch[:0]) - hex.Encode(scratch[:cap(scratch)], scratch[:sha256.Size]) - return string(scratch[:sha256.Size*2]) + // The first sha256.Size bytes contain the hash. + // Hex-encode that into the next sha256.Size*2 bytes. + src := scratch[:sha256.Size] + dst := scratch[sha256.Size:cap(scratch)] + n := hex.Encode(dst, src) + return string(dst[:n]) } // UpdateHash sets last to the hash of v and reports whether its value changed. diff --git a/internal/deephash/deephash_test.go b/internal/deephash/deephash_test.go index 047bc67dc..5b5e9a24c 100644 --- a/internal/deephash/deephash_test.go +++ b/internal/deephash/deephash_test.go @@ -134,3 +134,14 @@ func BenchmarkHashMapAcyclic(b *testing.B) { } } } + +func TestExhaustive(t *testing.T) { + seen := make(map[string]bool) + for i := 0; i < 100000; i++ { + s := calcHash(i) + if seen[s] { + t.Fatalf("hash collision %v", i) + } + seen[s] = true + } +}