diff options
| author | bors <bors@rust-lang.org> | 2015-12-10 18:11:32 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2015-12-10 18:11:32 +0000 |
| commit | ce132752c68aebbaf78125df4266e96e00261d36 (patch) | |
| tree | d8572dcc89640d12d2b83bee9d9bfdba91c6116c /src/libstd/thread | |
| parent | 41a33852b8ededcb3edd62d2e0ab7fca9fbf324f (diff) | |
| parent | 9e0ff773ad5840af78ef0deeebb7da2f503eca32 (diff) | |
| download | rust-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.rs | 17 |
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() } |
