diff options
Diffstat (limited to 'src/hash/crc32')
-rw-r--r-- | src/hash/crc32/crc32.go | 16 | ||||
-rw-r--r-- | src/hash/crc32/crc32_test.go | 10 |
2 files changed, 20 insertions, 6 deletions
diff --git a/src/hash/crc32/crc32.go b/src/hash/crc32/crc32.go index 908b84adcb..f330fdb77a 100644 --- a/src/hash/crc32/crc32.go +++ b/src/hash/crc32/crc32.go @@ -16,6 +16,7 @@ import ( "errors" "hash" "sync" + "sync/atomic" ) // The size of a CRC-32 checksum in bytes. @@ -78,6 +79,7 @@ var castagnoliTable8 *slicing8Table var castagnoliArchImpl bool var updateCastagnoli func(crc uint32, p []byte) uint32 var castagnoliOnce sync.Once +var haveCastagnoli uint32 func castagnoliInit() { castagnoliTable = simpleMakeTable(Castagnoli) @@ -93,6 +95,8 @@ func castagnoliInit() { return slicingUpdate(crc, castagnoliTable8, p) } } + + atomic.StoreUint32(&haveCastagnoli, 1) } // IEEETable is the table for the IEEE polynomial. @@ -208,10 +212,10 @@ func readUint32(b []byte) uint32 { // Update returns the result of adding the bytes in p to the crc. func Update(crc uint32, tab *Table, p []byte) uint32 { - switch tab { - case castagnoliTable: + switch { + case atomic.LoadUint32(&haveCastagnoli) != 0 && tab == castagnoliTable: return updateCastagnoli(crc, p) - case IEEETable: + case tab == IEEETable: // Unfortunately, because IEEETable is exported, IEEE may be used without a // call to MakeTable. We have to make sure it gets initialized in that case. ieeeOnce.Do(ieeeInit) @@ -222,10 +226,10 @@ func Update(crc uint32, tab *Table, p []byte) uint32 { } func (d *digest) Write(p []byte) (n int, err error) { - switch d.tab { - case castagnoliTable: + switch { + case atomic.LoadUint32(&haveCastagnoli) != 0 && d.tab == castagnoliTable: d.crc = updateCastagnoli(d.crc, p) - case IEEETable: + case d.tab == IEEETable: // We only create digest objects through New() which takes care of // initialization in this case. d.crc = updateIEEE(d.crc, p) diff --git a/src/hash/crc32/crc32_test.go b/src/hash/crc32/crc32_test.go index 4bdafaf8f5..cbb869dfd6 100644 --- a/src/hash/crc32/crc32_test.go +++ b/src/hash/crc32/crc32_test.go @@ -13,6 +13,16 @@ import ( "testing" ) +// First test, so that it can be the one to initialize castagnoliTable. +func TestCastagnoliRace(t *testing.T) { + // The MakeTable(Castagnoli) lazily initializes castagnoliTable, + // which races with the switch on tab during Write to check + // whether tab == castagnoliTable. + ieee := NewIEEE() + go MakeTable(Castagnoli) + ieee.Write([]byte("hello")) +} + type test struct { ieee, castagnoli uint32 in string |