diff options
| author | Javier Blazquez <[email protected]> | 2022-09-10 13:09:45 -0700 |
|---|---|---|
| committer | Jack O'Connor <[email protected]> | 2023-07-21 19:18:40 -0700 |
| commit | 12823b87604cbb7bcd0e5cdc347a53f80b2a617c (patch) | |
| tree | 5f8dd3544d035ad3ffe769170b792c3846edb650 /c | |
| parent | e302cdf36f1a8f3b9833b151c6c57964053cd587 (diff) | |
blake3_dispatch: Fix race condition initializing g_cpu_features.
If multiple threads try to compute a hash simultaneously before the library has been used for the first time,
the logic in get_cpu_features that detects CPU features will write to g_cpu_features without synchronization,
which is a race condition and flagged by ThreadSanitizer.
This change marks g_cpu_features as an atomic variable to address the race condition.
Diffstat (limited to 'c')
| -rw-r--r-- | c/blake3_dispatch.c | 39 |
1 files changed, 34 insertions, 5 deletions
diff --git a/c/blake3_dispatch.c b/c/blake3_dispatch.c index 2ab0093..af6c3da 100644 --- a/c/blake3_dispatch.c +++ b/c/blake3_dispatch.c @@ -6,6 +6,7 @@ #if defined(IS_X86) #if defined(_MSC_VER) +#include <Windows.h> #include <intrin.h> #elif defined(__GNUC__) #include <immintrin.h> @@ -14,6 +15,32 @@ #endif #endif +#if !defined(BLAKE3_ATOMICS) +#if defined(__has_include) +#if __has_include(<stdatomic.h>) && !defined(_MSC_VER) +#define BLAKE3_ATOMICS 1 +#else +#define BLAKE3_ATOMICS 0 +#endif /* __has_include(<stdatomic.h>) && !defined(_MSC_VER) */ +#else +#define BLAKE3_ATOMICS 0 +#endif /* defined(__has_include) */ +#endif /* BLAKE3_ATOMICS */ + +#if BLAKE3_ATOMICS +#define ATOMIC_INT _Atomic int +#define ATOMIC_LOAD(x) x +#define ATOMIC_STORE(x, y) x = y +#elif defined(_MSC_VER) +#define ATOMIC_INT LONG +#define ATOMIC_LOAD(x) InterlockedOr(&x, 0) +#define ATOMIC_STORE(x, y) InterlockedExchange(&x, y) +#else +#define ATOMIC_INT int +#define ATOMIC_LOAD(x) x +#define ATOMIC_STORE(x, y) x = y +#endif + #define MAYBE_UNUSED(x) (void)((x)) #if defined(IS_X86) @@ -76,7 +103,7 @@ enum cpu_feature { #if !defined(BLAKE3_TESTING) static /* Allow the variable to be controlled manually for testing */ #endif - enum cpu_feature g_cpu_features = UNDEFINED; + ATOMIC_INT g_cpu_features = UNDEFINED; #if !defined(BLAKE3_TESTING) static @@ -84,14 +111,16 @@ static enum cpu_feature get_cpu_features(void) { - if (g_cpu_features != UNDEFINED) { - return g_cpu_features; + /* If TSAN detects a data race here, try compiling with -DBLAKE3_ATOMICS=1 */ + enum cpu_feature features = ATOMIC_LOAD(g_cpu_features); + if (features != UNDEFINED) { + return features; } else { #if defined(IS_X86) uint32_t regs[4] = {0}; uint32_t *eax = ®s[0], *ebx = ®s[1], *ecx = ®s[2], *edx = ®s[3]; (void)edx; - enum cpu_feature features = 0; + features = 0; cpuid(regs, 0); const int max_id = *eax; cpuid(regs, 1); @@ -124,7 +153,7 @@ static } } } - g_cpu_features = features; + ATOMIC_STORE(g_cpu_features, features); return features; #else /* How to detect NEON? */ |
