Skip to content

Commit 528c4f9

Browse files
committed
Add PanicInfo::can_unwind which indicates whether a panic handler is
allowed to trigger unwinding.
1 parent bd3cb52 commit 528c4f9

File tree

4 files changed

+31
-10
lines changed

4 files changed

+31
-10
lines changed

library/core/src/panic/panic_info.rs

+15-1
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ pub struct PanicInfo<'a> {
3131
payload: &'a (dyn Any + Send),
3232
message: Option<&'a fmt::Arguments<'a>>,
3333
location: &'a Location<'a>,
34+
can_unwind: bool,
3435
}
3536

3637
impl<'a> PanicInfo<'a> {
@@ -44,9 +45,10 @@ impl<'a> PanicInfo<'a> {
4445
pub fn internal_constructor(
4546
message: Option<&'a fmt::Arguments<'a>>,
4647
location: &'a Location<'a>,
48+
can_unwind: bool,
4749
) -> Self {
4850
struct NoPayload;
49-
PanicInfo { location, message, payload: &NoPayload }
51+
PanicInfo { location, message, payload: &NoPayload, can_unwind }
5052
}
5153

5254
#[unstable(
@@ -127,6 +129,18 @@ impl<'a> PanicInfo<'a> {
127129
// deal with that case in std::panicking::default_hook and core::panicking::panic_fmt.
128130
Some(&self.location)
129131
}
132+
133+
/// Returns whether the panic handler is allowed to unwind the stack from
134+
/// the point where the panic occurred.
135+
///
136+
/// This is true for most kinds of panics with the exception of panics
137+
/// caused by trying to unwind out of a `Drop` implementation or a function
138+
/// whose ABI does not support unwinding.
139+
#[must_use]
140+
#[unstable(feature = "panic_can_unwind", issue = "92988")]
141+
pub fn can_unwind(&self) -> bool {
142+
self.can_unwind
143+
}
130144
}
131145

132146
#[stable(feature = "panic_hook_display", since = "1.26.0")]

library/core/src/panicking.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! {
104104
fn panic_impl(pi: &PanicInfo<'_>) -> !;
105105
}
106106

107-
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller());
107+
let pi = PanicInfo::internal_constructor(Some(&fmt), Location::caller(), true);
108108

109109
// SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call.
110110
unsafe { panic_impl(&pi) }

library/std/src/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,7 @@
312312
#![feature(once_cell)]
313313
#![feature(panic_info_message)]
314314
#![feature(panic_internals)]
315+
#![feature(panic_can_unwind)]
315316
#![feature(panic_unwind)]
316317
#![feature(pin_static_ref)]
317318
#![feature(portable_simd)]

library/std/src/panicking.rs

+14-8
Original file line numberDiff line numberDiff line change
@@ -576,9 +576,14 @@ pub fn begin_panic_handler(info: &PanicInfo<'_>) -> ! {
576576
let msg = info.message().unwrap(); // The current implementation always returns Some
577577
crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
578578
if let Some(msg) = msg.as_str() {
579-
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc);
579+
rust_panic_with_hook(&mut StrPanicPayload(msg), info.message(), loc, info.can_unwind());
580580
} else {
581-
rust_panic_with_hook(&mut PanicPayload::new(msg), info.message(), loc);
581+
rust_panic_with_hook(
582+
&mut PanicPayload::new(msg),
583+
info.message(),
584+
loc,
585+
info.can_unwind(),
586+
);
582587
}
583588
})
584589
}
@@ -602,7 +607,7 @@ pub const fn begin_panic<M: Any + Send>(msg: M) -> ! {
602607

603608
let loc = Location::caller();
604609
return crate::sys_common::backtrace::__rust_end_short_backtrace(move || {
605-
rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc)
610+
rust_panic_with_hook(&mut PanicPayload::new(msg), None, loc, true)
606611
});
607612

608613
struct PanicPayload<A> {
@@ -647,6 +652,7 @@ fn rust_panic_with_hook(
647652
payload: &mut dyn BoxMeUp,
648653
message: Option<&fmt::Arguments<'_>>,
649654
location: &Location<'_>,
655+
can_unwind: bool,
650656
) -> ! {
651657
let (must_abort, panics) = panic_count::increase();
652658

@@ -663,14 +669,14 @@ fn rust_panic_with_hook(
663669
} else {
664670
// Unfortunately, this does not print a backtrace, because creating
665671
// a `Backtrace` will allocate, which we must to avoid here.
666-
let panicinfo = PanicInfo::internal_constructor(message, location);
672+
let panicinfo = PanicInfo::internal_constructor(message, location, can_unwind);
667673
rtprintpanic!("{}\npanicked after panic::always_abort(), aborting.\n", panicinfo);
668674
}
669-
intrinsics::abort()
675+
crate::sys::abort_internal();
670676
}
671677

672678
unsafe {
673-
let mut info = PanicInfo::internal_constructor(message, location);
679+
let mut info = PanicInfo::internal_constructor(message, location, can_unwind);
674680
let _guard = HOOK_LOCK.read();
675681
match HOOK {
676682
// Some platforms (like wasm) know that printing to stderr won't ever actually
@@ -691,13 +697,13 @@ fn rust_panic_with_hook(
691697
};
692698
}
693699

694-
if panics > 1 {
700+
if panics > 1 || !can_unwind {
695701
// If a thread panics while it's already unwinding then we
696702
// have limited options. Currently our preference is to
697703
// just abort. In the future we may consider resuming
698704
// unwinding or otherwise exiting the thread cleanly.
699705
rtprintpanic!("thread panicked while panicking. aborting.\n");
700-
intrinsics::abort()
706+
crate::sys::abort_internal();
701707
}
702708

703709
rust_panic(payload)

0 commit comments

Comments
 (0)