From 538ddb0ac2a3f15ac43bd0444b36b755354f525e Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 25 Apr 2024 11:05:01 -0700 Subject: [PATCH 1/3] thread_local: use less &mut T in LazyKeyInner::take Instead, use raw pointers to accomplish internal mutability throughout. --- library/std/src/sys/thread_local/mod.rs | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 8b2c839f837d4..4fcea052ed0a9 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -91,13 +91,15 @@ mod lazy { } } - /// The other methods hand out references while taking &self. - /// As such, callers of this method must ensure no `&` and `&mut` are - /// available and used at the same time. + /// Watch out: unsynchronized internal mutability! + /// + /// # Safety + /// Unsound if called while any `&'static T` is active. #[allow(unused)] - pub unsafe fn take(&mut self) -> Option { - // SAFETY: See doc comment for this method. - unsafe { (*self.inner.get()).take() } + pub(crate) unsafe fn take(&self) -> Option { + let mutable: *mut _ = UnsafeCell::get(&self.inner); + // SAFETY: That's the caller's problem. + unsafe { mutable.replace(None) } } } } From 43f21a6871542df7546d9858d258207d947d3d2c Mon Sep 17 00:00:00 2001 From: Jubilee Young Date: Thu, 25 Apr 2024 12:32:11 -0700 Subject: [PATCH 2/3] thread_local: split refs to fields of Key --- library/std/src/sys/thread_local/fast_local.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/library/std/src/sys/thread_local/fast_local.rs b/library/std/src/sys/thread_local/fast_local.rs index 69ee70de30c02..49b51a729e428 100644 --- a/library/std/src/sys/thread_local/fast_local.rs +++ b/library/std/src/sys/thread_local/fast_local.rs @@ -1,7 +1,7 @@ use super::lazy::LazyKeyInner; use crate::cell::Cell; use crate::sys::thread_local_dtor::register_dtor; -use crate::{fmt, mem, panic}; +use crate::{fmt, mem, panic, ptr}; #[doc(hidden)] #[allow_internal_unstable(thread_local_internals, cfg_target_thread_local, thread_local)] @@ -237,8 +237,9 @@ unsafe extern "C" fn destroy_value(ptr: *mut u8) { // Wrap the call in a catch to ensure unwinding is caught in the event // a panic takes place in a destructor. if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe { - let value = (*ptr).inner.take(); - (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + let Key { inner, dtor_state } = &*ptr; + let value = inner.take(); + dtor_state.set(DtorState::RunningOrHasRun); drop(value); })) { rtabort!("thread local panicked on drop"); From c63b0ceb94c4c953f080ff0c543a950737408ff7 Mon Sep 17 00:00:00 2001 From: Jubilee <46493976+workingjubilee@users.noreply.github.com> Date: Fri, 26 Apr 2024 18:28:46 -0700 Subject: [PATCH 3/3] thread_local: refine LazyKeyInner::take safety doc Co-authored-by: joboet --- library/std/src/sys/thread_local/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/library/std/src/sys/thread_local/mod.rs b/library/std/src/sys/thread_local/mod.rs index 4fcea052ed0a9..7500c95d8b473 100644 --- a/library/std/src/sys/thread_local/mod.rs +++ b/library/std/src/sys/thread_local/mod.rs @@ -94,7 +94,7 @@ mod lazy { /// Watch out: unsynchronized internal mutability! /// /// # Safety - /// Unsound if called while any `&'static T` is active. + /// Causes UB if any reference to the value is used after this. #[allow(unused)] pub(crate) unsafe fn take(&self) -> Option { let mutable: *mut _ = UnsafeCell::get(&self.inner);