Skip to content

Commit c962372

Browse files
committed
Handle inline asm in has_ffi_unwind_calls
This is required for the soundness of options(may_unwind)
1 parent 7934bbd commit c962372

File tree

5 files changed

+71
-0
lines changed

5 files changed

+71
-0
lines changed

compiler/rustc_mir_transform/messages.ftl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
11
mir_transform_arithmetic_overflow = this arithmetic operation will overflow
2+
3+
mir_transform_asm_unwind_call = call to inline assembly that may unwind
4+
25
mir_transform_const_defined_here = `const` item defined here
36
47
mir_transform_const_modify = attempting to modify a `const` item

compiler/rustc_mir_transform/src/errors.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -143,6 +143,13 @@ impl AssertLintKind {
143143
}
144144
}
145145

146+
#[derive(LintDiagnostic)]
147+
#[diag(mir_transform_asm_unwind_call)]
148+
pub(crate) struct AsmUnwindCall {
149+
#[label(mir_transform_asm_unwind_call)]
150+
pub span: Span,
151+
}
152+
146153
#[derive(LintDiagnostic)]
147154
#[diag(mir_transform_ffi_unwind_call)]
148155
pub(crate) struct FfiUnwindCall {

compiler/rustc_mir_transform/src/ffi_unwind_calls.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use rustc_abi::ExternAbi;
2+
use rustc_ast::InlineAsmOptions;
23
use rustc_hir::def_id::{LOCAL_CRATE, LocalDefId};
34
use rustc_middle::mir::*;
45
use rustc_middle::query::{LocalCrate, Providers};
@@ -46,6 +47,34 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
4647
continue;
4748
}
4849
let Some(terminator) = &block.terminator else { continue };
50+
51+
if let TerminatorKind::InlineAsm { options, .. } = &terminator.kind {
52+
if options.contains(InlineAsmOptions::MAY_UNWIND) {
53+
// We have detected an inline asm block that can possibly leak foreign unwind.
54+
//
55+
// Because the function body itself can unwind, we are not aborting this function call
56+
// upon unwind, so this call can possibly leak foreign unwind into Rust code if the
57+
// panic runtime linked is panic-abort.
58+
59+
let lint_root = body.source_scopes[terminator.source_info.scope]
60+
.local_data
61+
.as_ref()
62+
.unwrap_crate_local()
63+
.lint_root;
64+
let span = terminator.source_info.span;
65+
66+
tcx.emit_node_span_lint(
67+
FFI_UNWIND_CALLS,
68+
lint_root,
69+
span,
70+
errors::AsmUnwindCall { span },
71+
);
72+
73+
tainted = true;
74+
}
75+
continue;
76+
}
77+
4978
let TerminatorKind::Call { func, .. } = &terminator.kind else { continue };
5079

5180
let ty = func.ty(body, tcx);
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// Check that asm!() with options(may_unwind) is considered an FFI call by has_ffi_unwind_calls.
2+
3+
//@ check-fail
4+
//@ needs-asm-support
5+
//@ needs-unwind
6+
7+
#![feature(asm_unwind)]
8+
#![deny(ffi_unwind_calls)]
9+
10+
use std::arch::asm;
11+
12+
#[no_mangle]
13+
pub unsafe fn asm_may_unwind() {
14+
asm!("", options(may_unwind));
15+
//~^ ERROR call to inline assembly that may unwind
16+
}
17+
18+
fn main() {}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: call to inline assembly that may unwind
2+
--> $DIR/may_unwind_ffi_unwind.rs:15:5
3+
|
4+
LL | asm!("", options(may_unwind));
5+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ call to inline assembly that may unwind
6+
|
7+
note: the lint level is defined here
8+
--> $DIR/may_unwind_ffi_unwind.rs:9:9
9+
|
10+
LL | #![deny(ffi_unwind_calls)]
11+
| ^^^^^^^^^^^^^^^^
12+
13+
error: aborting due to 1 previous error
14+

0 commit comments

Comments
 (0)