about summary refs log tree commit diff
path: root/src/libstd
diff options
context:
space:
mode:
authorAlex Crichton <alex@alexcrichton.com>2015-12-08 07:23:37 -0800
committerAlex Crichton <alex@alexcrichton.com>2015-12-08 12:23:22 -0800
commit9e0ff773ad5840af78ef0deeebb7da2f503eca32 (patch)
treea8e6e7f86a160227754bb9d16db59b998560675f /src/libstd
parent8864f2c83ac800881da34c3e835c931c081a8785 (diff)
downloadrust-9e0ff773ad5840af78ef0deeebb7da2f503eca32.tar.gz
rust-9e0ff773ad5840af78ef0deeebb7da2f503eca32.zip
std: Use mem::replace in TLS initialization
Due to #30228 it's not currently sound to do `*ptr = Some(value)`, so instead
use `mem::replace` which fixes the soundness hole for now.
Diffstat (limited to 'src/libstd')
-rw-r--r--src/libstd/thread/local.rs17
1 files changed, 16 insertions, 1 deletions
diff --git a/src/libstd/thread/local.rs b/src/libstd/thread/local.rs
index 119429cc584..870247f7e82 100644
--- a/src/libstd/thread/local.rs
+++ b/src/libstd/thread/local.rs
@@ -13,6 +13,7 @@
 #![unstable(feature = "thread_local_internals", issue = "0")]
 
 use cell::UnsafeCell;
+use mem;
 
 // Sure wish we had macro hygiene, no?
 #[doc(hidden)]
@@ -226,7 +227,21 @@ impl<T: 'static> LocalKey<T> {
         // just in case initialization fails.
         let value = (self.init)();
         let ptr = slot.get();
-        *ptr = Some(value);
+
+        // note that this can in theory just be `*ptr = Some(value)`, but due to
+        // the compiler will currently codegen that pattern with something like:
+        //
+        //      ptr::drop_in_place(ptr)
+        //      ptr::write(ptr, Some(value))
+        //
+        // Due to this pattern it's possible for the destructor of the value in
+        // `ptr` (e.g. if this is being recursively initialized) to re-access
+        // TLS, in which case there will be a `&` and `&mut` pointer to the same
+        // value (an aliasing violation). To avoid setting the "I'm running a
+        // destructor" flag we just use `mem::replace` which should sequence the
+        // operations a little differently and make this safe to call.
+        mem::replace(&mut *ptr, Some(value));
+
         (*ptr).as_ref().unwrap()
     }