@@ -141,9 +141,15 @@ impl StaticKey {
141141 panic ! ( "out of TLS indexes" ) ;
142142 }
143143
144- self . key . store ( key + 1 , Release ) ;
145144 register_dtor ( self ) ;
146145
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+
147153 let r = c:: InitOnceComplete ( self . once . get ( ) , 0 , ptr:: null_mut ( ) ) ;
148154 debug_assert_eq ! ( r, c:: TRUE ) ;
149155
@@ -313,17 +319,29 @@ unsafe fn run_dtors() {
313319 // Use acquire ordering to observe key initialization.
314320 let mut cur = DTORS . load ( Acquire ) ;
315321 while !cur. is_null ( ) {
316- let key = ( * cur) . key . load ( Relaxed ) - 1 ;
322+ let pre_key = ( * cur) . key . load ( Acquire ) ;
317323 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 ;
318338
319339 let ptr = c:: TlsGetValue ( key) ;
320340 if !ptr. is_null ( ) {
321341 c:: TlsSetValue ( key, ptr:: null_mut ( ) ) ;
322342 dtor ( ptr as * mut _ ) ;
323343 any_run = true ;
324344 }
325-
326- cur = ( * cur) . next . load ( Relaxed ) ;
327345 }
328346
329347 if !any_run {
0 commit comments