From 9e0ff773ad5840af78ef0deeebb7da2f503eca32 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 8 Dec 2015 07:23:37 -0800 Subject: 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. --- src/libstd/thread/local.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) (limited to 'src/libstd/thread') 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 LocalKey { // 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() } -- cgit 1.4.1-3-g733a5