From d3c580db2197e59603c2fdb8f111b684885d4096 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 20 Nov 2025 14:22:32 +0000 Subject: [PATCH] Handle inline asm in has_ffi_unwind_calls This is required for the soundness of options(may_unwind) --- compiler/rustc_mir_transform/messages.ftl | 3 ++ compiler/rustc_mir_transform/src/errors.rs | 7 +++++ .../src/ffi_unwind_calls.rs | 29 +++++++++++++++++++ tests/ui/asm/may_unwind_ffi_unwind.rs | 18 ++++++++++++ tests/ui/asm/may_unwind_ffi_unwind.stderr | 14 +++++++++ 5 files changed, 71 insertions(+) create mode 100644 tests/ui/asm/may_unwind_ffi_unwind.rs create mode 100644 tests/ui/asm/may_unwind_ffi_unwind.stderr diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl index cfc9b8edf7a28..7924c015200f1 100644 --- a/compiler/rustc_mir_transform/messages.ftl +++ b/compiler/rustc_mir_transform/messages.ftl @@ -1,4 +1,7 @@ mir_transform_arithmetic_overflow = this arithmetic operation will overflow + +mir_transform_asm_unwind_call = call to inline assembly that may unwind + mir_transform_const_defined_here = `const` item defined here mir_transform_const_modify = attempting to modify a `const` item diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs index 517e4dd692625..ee21d4fbceadc 100644 --- a/compiler/rustc_mir_transform/src/errors.rs +++ b/compiler/rustc_mir_transform/src/errors.rs @@ -143,6 +143,13 @@ impl AssertLintKind { } } +#[derive(LintDiagnostic)] +#[diag(mir_transform_asm_unwind_call)] +pub(crate) struct AsmUnwindCall { + #[label(mir_transform_asm_unwind_call)] + pub span: Span, +} + #[derive(LintDiagnostic)] #[diag(mir_transform_ffi_unwind_call)] pub(crate) struct FfiUnwindCall { diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs index 7c66783548ea4..06e7bf974b515 100644 --- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs +++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs @@ -1,4 +1,5 @@ use rustc_abi::ExternAbi; +use rustc_ast::InlineAsmOptions; use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId}; use rustc_middle::mir::*; use rustc_middle::query::{LocalCrate, Providers}; @@ -46,6 +47,34 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool { continue; } let Some(terminator) = &block.terminator else { continue }; + + if let TerminatorKind::InlineAsm { options, .. } = &terminator.kind { + if options.contains(InlineAsmOptions::MAY_UNWIND) { + // We have detected an inline asm block that can possibly leak foreign unwind. + // + // Because the function body itself can unwind, we are not aborting this function call + // upon unwind, so this call can possibly leak foreign unwind into Rust code if the + // panic runtime linked is panic-abort. + + let lint_root = body.source_scopes[terminator.source_info.scope] + .local_data + .as_ref() + .unwrap_crate_local() + .lint_root; + let span = terminator.source_info.span; + + tcx.emit_node_span_lint( + FFI_UNWIND_CALLS, + lint_root, + span, + errors::AsmUnwindCall { span }, + ); + + tainted = true; + } + continue; + } + let TerminatorKind::Call { func, .. } = &terminator.kind else { continue }; let ty = func.ty(body, tcx); diff --git a/tests/ui/asm/may_unwind_ffi_unwind.rs b/tests/ui/asm/may_unwind_ffi_unwind.rs new file mode 100644 index 0000000000000..65e2adac0a970 --- /dev/null +++ b/tests/ui/asm/may_unwind_ffi_unwind.rs @@ -0,0 +1,18 @@ +// Check that asm!() with options(may_unwind) is considered an FFI call by has_ffi_unwind_calls. + +//@ check-fail +//@ needs-asm-support +//@ needs-unwind + +#![feature(asm_unwind)] +#![deny(ffi_unwind_calls)] + +use std::arch::asm; + +#[no_mangle] +pub unsafe fn asm_may_unwind() { + asm!("", options(may_unwind)); + //~^ ERROR call to inline assembly that may unwind +} + +fn main() {} diff --git a/tests/ui/asm/may_unwind_ffi_unwind.stderr b/tests/ui/asm/may_unwind_ffi_unwind.stderr new file mode 100644 index 0000000000000..de24b601219eb --- /dev/null +++ b/tests/ui/asm/may_unwind_ffi_unwind.stderr @@ -0,0 +1,14 @@ +error: call to inline assembly that may unwind + --> $DIR/may_unwind_ffi_unwind.rs:14:5 + | +LL | asm!("", options(may_unwind)); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to inline assembly that may unwind + | +note: the lint level is defined here + --> $DIR/may_unwind_ffi_unwind.rs:8:9 + | +LL | #![deny(ffi_unwind_calls)] + | ^^^^^^^^^^^^^^^^ + +error: aborting due to 1 previous error +