about summary refs log tree commit diff
path: root/src/libstd/thread
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2015-12-10 18:11:32 +0000
committerbors <bors@rust-lang.org>2015-12-10 18:11:32 +0000
commitce132752c68aebbaf78125df4266e96e00261d36 (patch)
treed8572dcc89640d12d2b83bee9d9bfdba91c6116c /src/libstd/thread
parent41a33852b8ededcb3edd62d2e0ab7fca9fbf324f (diff)
parent9e0ff773ad5840af78ef0deeebb7da2f503eca32 (diff)
downloadrust-ce132752c68aebbaf78125df4266e96e00261d36.tar.gz
rust-ce132752c68aebbaf78125df4266e96e00261d36.zip
Auto merge of #30267 - alexcrichton:tls-init-oh-my, r=nikomatsakis
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/thread')
-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()
     }