diff options
| author | bors <bors@rust-lang.org> | 2022-12-30 12:58:50 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-12-30 12:58:50 +0000 |
| commit | 7c991868c60a4afc1ee6334b912ea96061a2c98d (patch) | |
| tree | 1fd5db269d4d75174efa69faec875cd91d748c2d | |
| parent | f6cc345be403d481b4518e151218118c2a9eb4bb (diff) | |
| parent | 04a6f22f7950daa680594353dbd03f5cb515aef5 (diff) | |
| download | rust-7c991868c60a4afc1ee6334b912ea96061a2c98d.tar.gz rust-7c991868c60a4afc1ee6334b912ea96061a2c98d.zip | |
Auto merge of #105426 - flba-eb:fix_tls_destructor_unwinding, r=m-ou-se
Catch panics/unwinding in destruction of TLS values `destroy_value` is/can be called from C code (libc). Unwinding from Rust to C code is undefined behavior, which is why unwinding is caught here. This problem caused an infinite loop inside the unwinding code when running `src/test/ui/threads-sendsync/issue-24313.rs` on a tier 3 target (QNX/Neutrino) on aarch64. See also https://rust-lang.zulipchat.com/#narrow/stream/182449-t-compiler.2Fhelp/topic/Infinite.20unwinding.20bug.
| -rw-r--r-- | library/std/src/thread/local.rs | 21 |
1 files changed, 14 insertions, 7 deletions
diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index 5d267891bb0..5f7e3a5dac9 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -905,9 +905,8 @@ pub mod statik { pub mod fast { use super::lazy::LazyKeyInner; use crate::cell::Cell; - use crate::fmt; - use crate::mem; use crate::sys::thread_local_dtor::register_dtor; + use crate::{fmt, mem, panic}; #[derive(Copy, Clone)] enum DtorState { @@ -1028,10 +1027,15 @@ pub mod fast { // `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This // causes future calls to `get` to run `try_initialize_drop` again, // which will now fail, and return `None`. - unsafe { + // + // 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); drop(value); + })) { + rtabort!("thread local panicked on drop"); } } } @@ -1044,10 +1048,8 @@ pub mod fast { pub mod os { use super::lazy::LazyKeyInner; use crate::cell::Cell; - use crate::fmt; - use crate::marker; - use crate::ptr; use crate::sys_common::thread_local_key::StaticKey as OsStaticKey; + use crate::{fmt, marker, panic, ptr}; /// Use a regular global static to store this key; the state provided will then be /// thread-local. @@ -1137,12 +1139,17 @@ pub mod os { // // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. - unsafe { + // + // 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(|| unsafe { let ptr = Box::from_raw(ptr as *mut Value<T>); let key = ptr.key; key.os.set(ptr::invalid_mut(1)); drop(ptr); key.os.set(ptr::null_mut()); + }) { + rtabort!("thread local panicked on drop"); } } } |
