Handle inline asm in has_ffi_unwind_calls

This is required for the soundness of options(may_unwind)
This commit is contained in:
bjorn3 2025-11-20 14:22:32 +00:00
parent 7934bbdf84
commit d3c580db21
5 changed files with 71 additions and 0 deletions

View file

@ -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

View file

@ -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 {

View file

@ -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);

View file

@ -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() {}

View file

@ -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