Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions compiler/rustc_mir_transform/messages.ftl
Original file line number Diff line number Diff line change
@@ -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
Expand Down
7 changes: 7 additions & 0 deletions compiler/rustc_mir_transform/src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
29 changes: 29 additions & 0 deletions compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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);
Expand Down
18 changes: 18 additions & 0 deletions tests/ui/asm/may_unwind_ffi_unwind.rs
Original file line number Diff line number Diff line change
@@ -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() {}
14 changes: 14 additions & 0 deletions tests/ui/asm/may_unwind_ffi_unwind.stderr
Original file line number Diff line number Diff line change
@@ -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

Loading