about summary refs log tree commit diff
diff options
context:
space:
mode:
authorOrson Peters <orsonpeters@gmail.com>2025-05-28 17:52:24 +0200
committerOrson Peters <orsonpeters@gmail.com>2025-05-28 17:53:14 +0200
commit9ffbc62cb60f2151a38b6c5e18c016e406d10a62 (patch)
treef5238d07e6c75b4d4cb0405ed8d94739f1c0794e
parent8785f7b122bbb83d308035565f243ceb95ce4736 (diff)
downloadrust-9ffbc62cb60f2151a38b6c5e18c016e406d10a62.tar.gz
rust-9ffbc62cb60f2151a38b6c5e18c016e406d10a62.zip
When replacing an old value we may not drop it in place
-rw-r--r--library/std/src/sys/thread_local/native/lazy.rs20
1 files changed, 8 insertions, 12 deletions
diff --git a/library/std/src/sys/thread_local/native/lazy.rs b/library/std/src/sys/thread_local/native/lazy.rs
index 2eb1c981edb..a2bf8d8b968 100644
--- a/library/std/src/sys/thread_local/native/lazy.rs
+++ b/library/std/src/sys/thread_local/native/lazy.rs
@@ -77,23 +77,19 @@ where
 
         let v = i.and_then(Option::take).unwrap_or_else(f);
 
+        // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer
+        // has already returned and the next scope only starts after we return
+        // the pointer. Therefore, there can be no references to the old value,
+        // even if it was initialized. Thus because we are !Sync we have exclusive
+        // access to self.value and may replace it.
+        let mut old_value = unsafe { self.value.get().replace(MaybeUninit::new(v)) };
         match self.state.replace(State::Alive) {
             State::Uninitialized => D::register_dtor(self),
-
-            State::Alive => {
-                // An init occurred during a recursive call, this could be a panic in the future.
-
-                // SAFETY: we cannot be inside a `LocalKey::with` scope, as the initializer
-                // has already returned and the next scope only starts after we return
-                // the pointer. Therefore, there can be no references to the old value.
-                unsafe { (*self.value.get()).assume_init_drop() }
-            }
-
+            State::Alive => unsafe { old_value.assume_init_drop() },
             State::Destroyed(_) => unreachable!(),
         }
 
-        // SAFETY: we are !Sync so we have exclusive access to self.value.
-        unsafe { (*self.value.get()).write(v) }
+        self.value.get().cast()
     }
 }