Skip to content

Commit 04a6f22

Browse files
committed
Catch panics 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.
1 parent d67000e commit 04a6f22

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

library/std/src/thread/local.rs

+14-7
Original file line numberDiff line numberDiff line change
@@ -905,9 +905,8 @@ pub mod statik {
905905
pub mod fast {
906906
use super::lazy::LazyKeyInner;
907907
use crate::cell::Cell;
908-
use crate::fmt;
909-
use crate::mem;
910908
use crate::sys::thread_local_dtor::register_dtor;
909+
use crate::{fmt, mem, panic};
911910

912911
#[derive(Copy, Clone)]
913912
enum DtorState {
@@ -1028,10 +1027,15 @@ pub mod fast {
10281027
// `Option<T>` to `None`, and `dtor_state` to `RunningOrHasRun`. This
10291028
// causes future calls to `get` to run `try_initialize_drop` again,
10301029
// which will now fail, and return `None`.
1031-
unsafe {
1030+
//
1031+
// Wrap the call in a catch to ensure unwinding is caught in the event
1032+
// a panic takes place in a destructor.
1033+
if let Err(_) = panic::catch_unwind(panic::AssertUnwindSafe(|| unsafe {
10321034
let value = (*ptr).inner.take();
10331035
(*ptr).dtor_state.set(DtorState::RunningOrHasRun);
10341036
drop(value);
1037+
})) {
1038+
rtabort!("thread local panicked on drop");
10351039
}
10361040
}
10371041
}
@@ -1044,10 +1048,8 @@ pub mod fast {
10441048
pub mod os {
10451049
use super::lazy::LazyKeyInner;
10461050
use crate::cell::Cell;
1047-
use crate::fmt;
1048-
use crate::marker;
1049-
use crate::ptr;
10501051
use crate::sys_common::thread_local_key::StaticKey as OsStaticKey;
1052+
use crate::{fmt, marker, panic, ptr};
10511053

10521054
/// Use a regular global static to store this key; the state provided will then be
10531055
/// thread-local.
@@ -1137,12 +1139,17 @@ pub mod os {
11371139
//
11381140
// Note that to prevent an infinite loop we reset it back to null right
11391141
// before we return from the destructor ourselves.
1140-
unsafe {
1142+
//
1143+
// Wrap the call in a catch to ensure unwinding is caught in the event
1144+
// a panic takes place in a destructor.
1145+
if let Err(_) = panic::catch_unwind(|| unsafe {
11411146
let ptr = Box::from_raw(ptr as *mut Value<T>);
11421147
let key = ptr.key;
11431148
key.os.set(ptr::invalid_mut(1));
11441149
drop(ptr);
11451150
key.os.set(ptr::null_mut());
1151+
}) {
1152+
rtabort!("thread local panicked on drop");
11461153
}
11471154
}
11481155
}

0 commit comments

Comments
 (0)