use cell::{Cell, UnsafeCell};
use intrinsics;
+ use ptr;
pub struct Key<T> {
inner: UnsafeCell<Option<T>>,
#[cfg(target_os = "linux")]
unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern fn(*mut u8)) {
use mem;
- use ptr;
use libc;
use sys_common::thread_local as os;
// destructor as running for this thread so calls to `get` will return
// `None`.
(*ptr).dtor_running.set(true);
- intrinsics::drop_in_place((*ptr).inner.get());
+
+ // The OSX implementation of TLS apparently had an odd aspect to it
+ // where the pointer we have may be overwritten while this destructor
+ // is running. Specifically if a TLS destructor re-accesses TLS it may
+ // trigger a re-initialization of all TLS variables, paving over at
+ // least some destroyed ones with initial values.
+ //
+ // This means that if we drop a TLS value in place on OSX that we could
+ // revert the value to its original state halfway through the
+ // destructor, which would be bad!
+ //
+ // Hence, we use `ptr::read` on OSX (to move to a "safe" location)
+ // instead of drop_in_place.
+ if cfg!(target_os = "macos") {
+ ptr::read((*ptr).inner.get());
+ } else {
+ intrinsics::drop_in_place((*ptr).inner.get());
+ }
}
}
--- /dev/null
+// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+thread_local!(static FOO: Foo = Foo);
+thread_local!(static BAR: Bar = Bar(1));
+thread_local!(static BAZ: Baz = Baz);
+
+struct Foo;
+struct Bar(i32);
+struct Baz;
+
+impl Drop for Foo {
+ fn drop(&mut self) {
+ BAR.with(|_| {});
+ }
+}
+
+impl Drop for Bar {
+ fn drop(&mut self) {
+ assert_eq!(self.0, 1);
+ self.0 = 2;
+ BAZ.with(|_| {});
+ assert_eq!(self.0, 2);
+ }
+}
+
+fn main() {
+ std::thread::spawn(|| {
+ FOO.with(|_| {});
+ }).join().unwrap();
+}