Add PanicInfo::can_unwind which indicates whether a panic handler is
allowed to trigger unwinding.
This commit is contained in:
parent
bd3cb52565
commit
528c4f9158
@ -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> {
|
||||
@ -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(
|
||||
@ -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")]
|
||||
|
@ -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) }
|
||||
|
@ -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)]
|
||||
|
@ -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(),
|
||||
);
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -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> {
|
||||
@ -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();
|
||||
|
||||
@ -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
|
||||
@ -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)
|
||||
|
Loading…
x
Reference in New Issue
Block a user