Skip to content

Commit 12823b8

Browse files
jblazquezoconnor663
authored andcommitted
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.
1 parent e302cdf commit 12823b8

File tree

1 file changed

+34
-5
lines changed

1 file changed

+34
-5
lines changed

c/blake3_dispatch.c

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
#if defined(IS_X86)
88
#if defined(_MSC_VER)
9+
#include <Windows.h>
910
#include <intrin.h>
1011
#elif defined(__GNUC__)
1112
#include <immintrin.h>
@@ -14,6 +15,32 @@
1415
#endif
1516
#endif
1617

18+
#if !defined(BLAKE3_ATOMICS)
19+
#if defined(__has_include)
20+
#if __has_include(<stdatomic.h>) && !defined(_MSC_VER)
21+
#define BLAKE3_ATOMICS 1
22+
#else
23+
#define BLAKE3_ATOMICS 0
24+
#endif /* __has_include(<stdatomic.h>) && !defined(_MSC_VER) */
25+
#else
26+
#define BLAKE3_ATOMICS 0
27+
#endif /* defined(__has_include) */
28+
#endif /* BLAKE3_ATOMICS */
29+
30+
#if BLAKE3_ATOMICS
31+
#define ATOMIC_INT _Atomic int
32+
#define ATOMIC_LOAD(x) x
33+
#define ATOMIC_STORE(x, y) x = y
34+
#elif defined(_MSC_VER)
35+
#define ATOMIC_INT LONG
36+
#define ATOMIC_LOAD(x) InterlockedOr(&x, 0)
37+
#define ATOMIC_STORE(x, y) InterlockedExchange(&x, y)
38+
#else
39+
#define ATOMIC_INT int
40+
#define ATOMIC_LOAD(x) x
41+
#define ATOMIC_STORE(x, y) x = y
42+
#endif
43+
1744
#define MAYBE_UNUSED(x) (void)((x))
1845

1946
#if defined(IS_X86)
@@ -76,22 +103,24 @@ enum cpu_feature {
76103
#if !defined(BLAKE3_TESTING)
77104
static /* Allow the variable to be controlled manually for testing */
78105
#endif
79-
enum cpu_feature g_cpu_features = UNDEFINED;
106+
ATOMIC_INT g_cpu_features = UNDEFINED;
80107

81108
#if !defined(BLAKE3_TESTING)
82109
static
83110
#endif
84111
enum cpu_feature
85112
get_cpu_features(void) {
86113

87-
if (g_cpu_features != UNDEFINED) {
88-
return g_cpu_features;
114+
/* If TSAN detects a data race here, try compiling with -DBLAKE3_ATOMICS=1 */
115+
enum cpu_feature features = ATOMIC_LOAD(g_cpu_features);
116+
if (features != UNDEFINED) {
117+
return features;
89118
} else {
90119
#if defined(IS_X86)
91120
uint32_t regs[4] = {0};
92121
uint32_t *eax = &regs[0], *ebx = &regs[1], *ecx = &regs[2], *edx = &regs[3];
93122
(void)edx;
94-
enum cpu_feature features = 0;
123+
features = 0;
95124
cpuid(regs, 0);
96125
const int max_id = *eax;
97126
cpuid(regs, 1);
@@ -124,7 +153,7 @@ static
124153
}
125154
}
126155
}
127-
g_cpu_features = features;
156+
ATOMIC_STORE(g_cpu_features, features);
128157
return features;
129158
#else
130159
/* How to detect NEON? */

0 commit comments

Comments
 (0)