Skip to content

Commit

Permalink
Add PanicInfo::can_unwind which indicates whether a panic handler is
Browse files Browse the repository at this point in the history
allowed to trigger unwinding.
  • Loading branch information
Amanieu committed Jan 17, 2022
1 parent bd3cb52 commit 528c4f9
Show file tree
Hide file tree
Showing 4 changed files with 31 additions and 10 deletions.
16 changes: 15 additions & 1 deletion library/core/src/panic/panic_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ pub struct PanicInfo<'a> {
payload: &'a (dyn Any + Send),
message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>,
can_unwind: bool,
}

impl<'a> PanicInfo<'a> {
Expand All @@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> {
pub fn internal_constructor(
message: Option<&'a fmt::Arguments<'a>>,
location: &'a Location<'a>,
can_unwind: bool,
) -> Self {
struct NoPayload;
PanicInfo { location, message, payload: &NoPayload }
PanicInfo { location, message, payload: &NoPayload, can_unwind }
}

#[unstable(
Expand Down Expand Up @@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> {
// deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
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")]
Expand Down
2 changes: 1 addition & 1 deletion library/core/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
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.
unsafe { panic_impl(&pi) }
Expand Down
1 change: 1 addition & 0 deletions library/std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -312,6 +312,7 @@
#![feature(once_cell)]
#![feature(panic_info_message)]
#![feature(panic_internals)]
#![feature(panic_can_unwind)]
#![feature(panic_unwind)]
#![feature(pin_static_ref)]
#![feature(portable_simd)]
Expand Down
22 changes: 14 additions & 8 deletions library/std/src/panicking.rs
Original file line number Diff line number Diff line change
Expand Up @@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
let msg = info.message().unwrap(); // The current implementation always returns Some
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
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 {
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(),
);
}
})
}
Expand All @@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {

let loc = Location::caller();
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> {
Expand Down Expand Up @@ -647,6 +652,7 @@ fn rust_panic_with_hook(
payload: &mut dyn BoxMeUp,
message: Option<&fmt::Arguments<'_>>,
location: &Location<'_>,
can_unwind: bool,
) -> ! {
let (must_abort, panics) = panic_count::increase();

Expand All @@ -663,14 +669,14 @@ fn rust_panic_with_hook(
} else {
// Unfortunately, this does not print a backtrace, because creating
// 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);
}
intrinsics::abort()
crate::sys::abort_internal();
}

unsafe {
let mut info = PanicInfo::internal_constructor(message, location);
let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
let _guard = HOOK_LOCK.read();
match HOOK {
// Some platforms (like wasm) know that printing to stderr won't ever actually
Expand All @@ -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
// have limited options. Currently our preference is to
// just abort. In the future we may consider resuming
// unwinding or otherwise exiting the thread cleanly.
rtprintpanic!("thread panicked while panicking. aborting.\n");
intrinsics::abort()
crate::sys::abort_internal();
}

rust_panic(payload)
Expand Down

0 comments on commit 528c4f9

Please sign in to comment.