1
Fork 0

Add PanicInfo::can_unwind which indicates whether a panic handler is

allowed to trigger unwinding.
This commit is contained in:
Amanieu d'Antras 2021-12-19 00:43:46 +01:00
parent bd3cb52565
commit 528c4f9158
4 changed files with 31 additions and 10 deletions

View file

@ -31,6 +31,7 @@ pub struct PanicInfo<'a> {
payload: &'a (dyn Any + Send), payload: &'a (dyn Any + Send),
message: Option<&'a fmt::Arguments<'a>>, message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>, location: &'a Location<'a>,
can_unwind: bool,
} }
impl<'a> PanicInfo<'a> { impl<'a> PanicInfo<'a> {
@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> {
pub fn internal_constructor( pub fn internal_constructor(
message: Option<&'a fmt::Arguments<'a>>, message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>, location: &'a Location<'a>,
can_unwind: bool,
) -> Self { ) -> Self {
struct NoPayload; struct NoPayload;
PanicInfo { location, message, payload: &NoPayload } PanicInfo { location, message, payload: &NoPayload, can_unwind }
} }
#[unstable( #[unstable(
@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> {
// deal with that case in std::panicking::default_hook and core::panicking::panic_fmt. // deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
Some(&self.location) Some(&self.location)
} }
/// Returns whether the panic handler is allowed to unwind the stack from
/// the point where the panic occurred.
///
/// This is true for most kinds of panics with the exception of panics
/// caused by trying to unwind out of a `Drop` implementation or a function
/// whose ABI does not support unwinding.
#[must_use]
#[unstable(feature = "panic_can_unwind", issue = "92988")]
pub fn can_unwind(&self) -> bool {
self.can_unwind
}
} }
#[stable(feature = "panic_hook_display", since = "1.26.0")] #[stable(feature = "panic_hook_display", since = "1.26.0")]

View file

@ -104,7 +104,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
fn panic_impl(pi: &PanicInfo<'_>) -> !; fn panic_impl(pi: &PanicInfo<'_>) -> !;
} }
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller()); let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
unsafe { panic_impl(&pi) } unsafe { panic_impl(&pi) }

View file

@ -312,6 +312,7 @@
#![feature(once_cell)] #![feature(once_cell)]
#![feature(panic_info_message)] #![feature(panic_info_message)]
#![feature(panic_internals)] #![feature(panic_internals)]
#![feature(panic_can_unwind)]
#![feature(panic_unwind)] #![feature(panic_unwind)]
#![feature(pin_static_ref)] #![feature(pin_static_ref)]
#![feature(portable_simd)] #![feature(portable_simd)]

View file

@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
let msg = info.message().unwrap(); // The current implementation always returns Some let msg = info.message().unwrap(); // The current implementation always returns Some
crate::sys_common::backtrace::__rust_end_short_backtrace(move || { crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
if let Some(msg) = msg.as_str() { if let Some(msg) = msg.as_str() {
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc); rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
} else { } else {
rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc); rust_panic_with_hook(
&mut PanicPayload::new(msg),
info.message(),
loc,
info.can_unwind(),
);
} }
}) })
} }
@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
let loc = Location::caller(); let loc = Location::caller();
return crate::sys_common::backtrace::__rust_end_short_backtrace(move || { return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc) rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
}); });
struct PanicPayload<A> { struct PanicPayload<A> {
@ -647,6 +652,7 @@ fn rust_panic_with_hook(
payload: &mut dyn BoxMeUp, payload: &mut dyn BoxMeUp,
message: Option<&fmt::Arguments<'_>>, message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>, location: &Location<'_>,
can_unwind: bool,
) -> ! { ) -> ! {
let (must_abort, panics) = panic_count::increase(); let (must_abort, panics) = panic_count::increase();
@ -663,14 +669,14 @@ fn rust_panic_with_hook(
} else { } else {
// Unfortunately, this does not print a backtrace, because creating // Unfortunately, this does not print a backtrace, because creating
// a `Backtrace` will allocate, which we must to avoid here. // a `Backtrace` will allocate, which we must to avoid here.
let panicinfo = PanicInfo::internal_constructor(message, location); let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo); rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
} }
intrinsics::abort() crate::sys::abort_internal();
} }
unsafe { unsafe {
let mut info = PanicInfo::internal_constructor(message, location); let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
let _guard = HOOK_LOCK.read(); let _guard = HOOK_LOCK.read();
match HOOK { match HOOK {
// Some platforms (like wasm) know that printing to stderr won't ever actually // Some platforms (like wasm) know that printing to stderr won't ever actually
@ -691,13 +697,13 @@ fn rust_panic_with_hook(
}; };
} }
if panics > 1 { if panics > 1 || !can_unwind {
// If a thread panics while it's already unwinding then we // If a thread panics while it's already unwinding then we
// have limited options. Currently our preference is to // have limited options. Currently our preference is to
// just abort. In the future we may consider resuming // just abort. In the future we may consider resuming
// unwinding or otherwise exiting the thread cleanly. // unwinding or otherwise exiting the thread cleanly.
rtprintpanic!("thread panicked while panicking. aborting.\n"); rtprintpanic!("thread panicked while panicking. aborting.\n");
intrinsics::abort() crate::sys::abort_internal();
} }
rust_panic(payload) rust_panic(payload)