From bd3ea3e09624140893c7679e45c65cb2fde1b4bf Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Feb 2024 15:00:49 +0100 Subject: [PATCH 1/2] ffi_unwind_calls: treat RustIntrinsic like regular Rust calls --- .../rustc_mir_transform/src/ffi_unwind_calls.rs | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 0dc06524c79..d9387ecd14c 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -10,6 +10,10 @@ use crate::errors; +/// Some of the functions declared as "may unwind" by `fn_can_unwind` can't actually unwind. In +/// particular, `extern "C"` is still considered as can-unwind on stable, but we need to to consider +/// it cannot-unwind here. So below we check `fn_can_unwind() && abi_can_unwind()` before concluding +/// that a function call can unwind. fn abi_can_unwind(abi: Abi) -> bool { use Abi::*; match abi { @@ -33,9 +37,8 @@ fn abi_can_unwind(abi: Abi) -> bool { | RiscvInterruptS | CCmseNonSecureCall | Wasm - | RustIntrinsic | Unadjusted => false, - Rust | RustCall | RustCold => true, + RustIntrinsic | Rust | RustCall | RustCold => unreachable!(), // these ABIs are already skipped earlier } } @@ -81,14 +84,16 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { let sig = ty.fn_sig(tcx); // Rust calls cannot themselves create foreign unwinds. - if let Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() { + // We assume this is true for intrinsics as well. + if let Abi::RustIntrinsic | Abi::Rust | Abi::RustCall | Abi::RustCold = sig.abi() { continue; }; let fn_def_id = match ty.kind() { ty::FnPtr(_) => None, &ty::FnDef(def_id, _) => { - // Rust calls cannot themselves create foreign unwinds. + // Rust calls cannot themselves create foreign unwinds (even if they use a non-Rust ABI). + // So the leak of the foreign unwind into Rust can only be elsewhere, not here. if !tcx.is_foreign_item(def_id) { continue; } From f5c80dcd5a7f7b7b9ef4d00ac9bfb68d9c789f6f Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 24 Feb 2024 15:07:16 +0100 Subject: [PATCH 2/2] intrinsics.rs: add some notes on unwinding --- library/core/src/intrinsics.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index 6fd3895bb9c..96e667d63c5 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -44,6 +44,15 @@ //! * Sequentially consistent - sequentially consistent operations are //! guaranteed to happen in order. This is the standard mode for working //! with atomic types and is equivalent to Java's `volatile`. +//! +//! # Unwinding +//! +//! Rust intrinsics may, in general, unwind. If an intrinsic can never unwind, add the +//! `#[rustc_nounwind]` attribute so that the compiler can make use of this fact. +//! +//! However, even for intrinsics that may unwind, rustc assumes that a Rust intrinsics will never +//! initiate a foreign (non-Rust) unwind, and thus for panic=abort we can always assume that these +//! intrinsics cannot unwind. #![unstable( feature = "core_intrinsics", @@ -692,6 +701,7 @@ pub unsafe fn drop_in_place(to_drop: *mut T) { /// The stabilized version of this intrinsic is available on the /// [`atomic`] signed integer types via the `fetch_min` method by passing /// [`Ordering::AcqRel`] as the `order`. For example, [`AtomicI32::fetch_min`]. + #[rustc_nounwind] pub fn atomic_min_acqrel(dst: *mut T, src: T) -> T; /// Minimum with the current value using a signed comparison. ///