Add PanicInfo::can_unwind which indicates whether a panic handler is
allowed to trigger unwinding.
This commit is contained in:
parent
bd3cb52565
commit
528c4f9158
4 changed files with 31 additions and 10 deletions
|
@ -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")]
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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)]
|
||||||
|
|
|
@ -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)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue