From 5961134fa5530e8e07b5536b9577e4755ac1e04a Mon Sep 17 00:00:00 2001 From: Joe Tsai <joetsai@digital-static.net> Date: Mon, 30 Aug 2021 10:25:11 -0700 Subject: [PATCH] crypto: avoid escaping Hash.Sum on generic architectures For architectures without a specialized implementation (e.g. arm), the generic implementation allocates because it does: var block = blockGeneric which causes the compiler to give up trying to analyze block even though it is technically only ever one implementation. Instead of a variable, declare a function that wraps blockGeneric. We apply this fix to md5, sha1, and sha256, while sha512 already had the equivalent change. We add a test to all hashing packages to ensure no allocations. Credit goes to Cuong Manh Le for more specifically identifying the problem and Keith Randal for suggesting a concrete solution. Fixes #48055 Change-Id: I1a6a2e028038e051c83fd72b10a8bf4d210df57d Reviewed-on: https://go-review.googlesource.com/c/go/+/346209 Trust: Joe Tsai <joetsai@digital-static.net> Run-TryBot: Joe Tsai <joetsai@digital-static.net> Reviewed-by: Filippo Valsorda <filippo@golang.org> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Keith Randall <khr@golang.org> TryBot-Result: Go Bot <gobot@golang.org> --- src/crypto/md5/md5_test.go | 14 ++++++++++++++ src/crypto/md5/md5block_generic.go | 4 +++- src/crypto/sha1/sha1_test.go | 14 ++++++++++++++ src/crypto/sha1/sha1block_generic.go | 4 +++- src/crypto/sha256/sha256_test.go | 14 ++++++++++++++ src/crypto/sha256/sha256block_generic.go | 4 +++- src/crypto/sha512/sha512_test.go | 14 ++++++++++++++ 7 files changed, 65 insertions(+), 3 deletions(-) diff --git a/src/crypto/md5/md5_test.go b/src/crypto/md5/md5_test.go index acd456af215..851e7fb10d4 100644 --- a/src/crypto/md5/md5_test.go +++ b/src/crypto/md5/md5_test.go @@ -211,6 +211,20 @@ func TestLargeHashes(t *testing.T) { } } +func TestAllocations(t *testing.T) { + in := []byte("hello, world!") + out := make([]byte, 0, Size) + h := New() + n := int(testing.AllocsPerRun(10, func() { + h.Reset() + h.Write(in) + out = h.Sum(out[:0]) + })) + if n > 0 { + t.Errorf("allocs = %d, want 0", n) + } +} + var bench = New() var buf = make([]byte, 1024*1024*8+1) var sum = make([]byte, bench.Size()) diff --git a/src/crypto/md5/md5block_generic.go b/src/crypto/md5/md5block_generic.go index ea4fbcd0b41..23ed75304f9 100644 --- a/src/crypto/md5/md5block_generic.go +++ b/src/crypto/md5/md5block_generic.go @@ -9,4 +9,6 @@ package md5 const haveAsm = false -var block = blockGeneric +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go index c3e6010af12..ab43c7792d4 100644 --- a/src/crypto/sha1/sha1_test.go +++ b/src/crypto/sha1/sha1_test.go @@ -210,6 +210,20 @@ func TestLargeHashes(t *testing.T) { } } +func TestAllocations(t *testing.T) { + in := []byte("hello, world!") + out := make([]byte, 0, Size) + h := New() + n := int(testing.AllocsPerRun(10, func() { + h.Reset() + h.Write(in) + out = h.Sum(out[:0]) + })) + if n > 0 { + t.Errorf("allocs = %d, want 0", n) + } +} + var bench = New() var buf = make([]byte, 8192) diff --git a/src/crypto/sha1/sha1block_generic.go b/src/crypto/sha1/sha1block_generic.go index feaba5a23ab..105aa318322 100644 --- a/src/crypto/sha1/sha1block_generic.go +++ b/src/crypto/sha1/sha1block_generic.go @@ -7,4 +7,6 @@ package sha1 -var block = blockGeneric +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go index a2794b015db..702aa0b371a 100644 --- a/src/crypto/sha256/sha256_test.go +++ b/src/crypto/sha256/sha256_test.go @@ -289,6 +289,20 @@ func TestLargeHashes(t *testing.T) { } } +func TestAllocations(t *testing.T) { + in := []byte("hello, world!") + out := make([]byte, 0, Size) + h := New() + n := int(testing.AllocsPerRun(10, func() { + h.Reset() + h.Write(in) + out = h.Sum(out[:0]) + })) + if n > 0 { + t.Errorf("allocs = %d, want 0", n) + } +} + var bench = New() var buf = make([]byte, 8192) diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go index 620c048b93c..0f2bf8b2315 100644 --- a/src/crypto/sha256/sha256block_generic.go +++ b/src/crypto/sha256/sha256block_generic.go @@ -7,4 +7,6 @@ package sha256 -var block = blockGeneric +func block(dig *digest, p []byte) { + blockGeneric(dig, p) +} diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go index 0e1528fc69f..aea772c7da5 100644 --- a/src/crypto/sha512/sha512_test.go +++ b/src/crypto/sha512/sha512_test.go @@ -888,6 +888,20 @@ func TestLargeHashes(t *testing.T) { } } +func TestAllocations(t *testing.T) { + in := []byte("hello, world!") + out := make([]byte, 0, Size) + h := New() + n := int(testing.AllocsPerRun(10, func() { + h.Reset() + h.Write(in) + out = h.Sum(out[:0]) + })) + if n > 0 { + t.Errorf("allocs = %d, want 0", n) + } +} + var bench = New() var buf = make([]byte, 8192) -- GitLab