about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAmanieu d'Antras <amanieu@gmail.com>2021-12-19 00:43:46 +0100
committerAmanieu d'Antras <amanieu@gmail.com>2022-01-17 00:39:28 +0000
commit528c4f9158ead3df8cecb51663db50e711fec377 (patch)
tree8a22999a5a1f57297f3d1e0d091b5cf91209dd94
parentbd3cb52565faab2755ff1bdb54d88bc91f47b4b9 (diff)
downloadrust-528c4f9158ead3df8cecb51663db50e711fec377.tar.gz
rust-528c4f9158ead3df8cecb51663db50e711fec377.zip
Add PanicInfo::can_unwind which indicates whether a panic handler is
allowed to trigger unwinding.
-rw-r--r--library/core/src/panic/panic_info.rs16
-rw-r--r--library/core/src/panicking.rs2
-rw-r--r--library/std/src/lib.rs1
-rw-r--r--library/std/src/panicking.rs22
4 files changed, 31 insertions, 10 deletions
diff --git a/library/core/src/panic/panic_info.rs b/library/core/src/panic/panic_info.rs
index d8e421df5de..405224f8fb0 100644
--- a/library/core/src/panic/panic_info.rs
+++ b/library/core/src/panic/panic_info.rs
@@ -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")]
diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs
index ccb82cda54e..f260f19127b 100644
--- a/library/core/src/panicking.rs
+++ b/library/core/src/panicking.rs
@@ -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) }
diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs
index 1721e16f3a6..0b2a864b7f7 100644
--- a/library/std/src/lib.rs
+++ b/library/std/src/lib.rs
@@ -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)]
diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs
index 44f573297ee..c08d693f81a 100644
--- a/library/std/src/panicking.rs
+++ b/library/std/src/panicking.rs
@@ -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)