diff options
author | Russ Cox <rsc@golang.org> | 2017-09-19 23:50:50 -0400 |
---|---|---|
committer | Russ Cox <rsc@golang.org> | 2017-09-20 18:01:53 +0000 |
commit | 2ba76155cd0762375b8e19a500a5b1fb875ff73b (patch) | |
tree | 70bf76012196dc0655b7e4e8e061e8185915ead9 /src/crypto/rsa/boring_test.go | |
parent | 32dc9b247fc8393d5effb31a6673c797d75db78e (diff) | |
download | go-2ba76155cd0762375b8e19a500a5b1fb875ff73b.tar.gz go-2ba76155cd0762375b8e19a500a5b1fb875ff73b.zip |
[dev.boringcrypto] crypto/internal/boring: fix finalizer-induced crashes
All the finalizer-enabled C wrappers must be careful to use
runtime.KeepAlive to ensure the C wrapper object (a Go object)
lives through the end of every C call using state that the
wrapper's finalizer would free.
This CL makes the wrappers appropriately careful.
The test proves that this is the bug I was chasing in a
separate real program, and that the KeepAlives fix it.
I did not write a test of every possible operation.
Change-Id: I627007e480f16adf8396e7f796b54e5525d9ea80
Reviewed-on: https://go-review.googlesource.com/64870
Run-TryBot: Russ Cox <rsc@golang.org>
Reviewed-by: Adam Langley <agl@golang.org>
Reviewed-by: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src/crypto/rsa/boring_test.go')
-rw-r--r-- | src/crypto/rsa/boring_test.go | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go index f40e2748ca..dfec83805f 100644 --- a/src/crypto/rsa/boring_test.go +++ b/src/crypto/rsa/boring_test.go @@ -16,7 +16,10 @@ import ( "encoding/asn1" "encoding/hex" "reflect" + "runtime" + "runtime/debug" "sync" + "sync/atomic" "testing" "unsafe" ) @@ -290,3 +293,41 @@ func TestBoringRandDecryptOAEP(t *testing.T) { } r.checkOffset(256) } + +func TestBoringFinalizers(t *testing.T) { + if runtime.GOOS == "nacl" { + // Times out on nacl (without BoringCrypto) + // but not clear why - probably consuming rand.Reader too quickly + // and being throttled. Also doesn't really matter. + t.Skip("skipping on nacl") + } + + k := testKey(t) + + // Run test with GOGC=10, to make bug more likely. + // Without the KeepAlives, the loop usually dies after + // about 30 iterations. + defer debug.SetGCPercent(debug.SetGCPercent(10)) + for n := 0; n < 200; n++ { + // Clear the underlying BoringCrypto object. + atomic.StorePointer(&k.boring, nil) + + // Race to create the underlying BoringCrypto object. + // The ones that lose the race are prime candidates for + // being GC'ed too early if the finalizers are not being + // used correctly. + var wg sync.WaitGroup + for i := 0; i < 10; i++ { + wg.Add(1) + go func() { + defer wg.Done() + sum := make([]byte, 32) + _, err := SignPKCS1v15(rand.Reader, k, crypto.SHA256, sum) + if err != nil { + panic(err) // usually caused by memory corruption, so hard stop + } + }() + } + wg.Wait() + } +} |