about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2022-12-30 12:58:50 +0000
committerbors <bors@rust-lang.org>2022-12-30 12:58:50 +0000
commit7c991868c60a4afc1ee6334b912ea96061a2c98d (patch)
tree1fd5db269d4d75174efa69faec875cd91d748c2d
parentf6cc345be403d481b4518e151218118c2a9eb4bb (diff)
parent04a6f22f7950daa680594353dbd03f5cb515aef5 (diff)
downloadrust-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.rs21
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");
         }
     }
 }