@@ -141,9 +141,15 @@ impl StaticKey {
141
141
panic ! ( "out of TLS indexes" ) ;
142
142
}
143
143
144
- self . key . store ( key + 1 , Release ) ;
145
144
register_dtor ( self ) ;
146
145
146
+ // Release-storing the key needs to be the last thing we do.
147
+ // This is because in `fn key()`, other threads will do an acquire load of the key,
148
+ // and if that sees this write then it will entirely bypass the `InitOnce`. We thus
149
+ // need to establish synchronization through `key`. In particular that acquire load
150
+ // must happen-after the register_dtor above, to ensure the dtor actually runs!
151
+ self . key . store ( key + 1 , Release ) ;
152
+
147
153
let r = c:: InitOnceComplete ( self . once . get ( ) , 0 , ptr:: null_mut ( ) ) ;
148
154
debug_assert_eq ! ( r, c:: TRUE ) ;
149
155
@@ -313,17 +319,29 @@ unsafe fn run_dtors() {
313
319
// Use acquire ordering to observe key initialization.
314
320
let mut cur = DTORS . load ( Acquire ) ;
315
321
while !cur. is_null ( ) {
316
- let key = ( * cur) . key . load ( Relaxed ) - 1 ;
322
+ let pre_key = ( * cur) . key . load ( Acquire ) ;
317
323
let dtor = ( * cur) . dtor . unwrap ( ) ;
324
+ cur = ( * cur) . next . load ( Relaxed ) ;
325
+
326
+ // In StaticKey::init, we register the dtor before setting `key`.
327
+ // So if one thread's `run_dtors` races with another thread executing `init` on the same
328
+ // `StaticKey`, we can encounter a key of 0 here. That means this key was never
329
+ // initialized in this thread so we can safely skip it.
330
+ if pre_key == 0 {
331
+ continue ;
332
+ }
333
+ // If this is non-zero, then via the `Acquire` load above we synchronized with
334
+ // everything relevant for this key. (It's not clear that this is needed, since the
335
+ // release-acquire pair on DTORS also establishes synchronization, but better safe than
336
+ // sorry.)
337
+ let key = pre_key - 1 ;
318
338
319
339
let ptr = c:: TlsGetValue ( key) ;
320
340
if !ptr. is_null ( ) {
321
341
c:: TlsSetValue ( key, ptr:: null_mut ( ) ) ;
322
342
dtor ( ptr as * mut _ ) ;
323
343
any_run = true ;
324
344
}
325
-
326
- cur = ( * cur) . next . load ( Relaxed ) ;
327
345
}
328
346
329
347
if !any_run {
0 commit comments