Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make destructors on extern "C" frames to be executed #129582

Merged
merged 3 commits into from
Oct 17, 2024
Merged
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
25 changes: 19 additions & 6 deletions compiler/rustc_mir_transform/src/abort_unwinding_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,11 +51,20 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
// This will filter to functions with `extern "C-unwind"` ABIs, for
// example.
for block in body.basic_blocks.as_mut() {
let Some(terminator) = &mut block.terminator else { continue };
let span = terminator.source_info.span;

// If we see an `UnwindResume` terminator inside a function that cannot unwind, we need
// to replace it with `UnwindTerminate`.
if let TerminatorKind::UnwindResume = &terminator.kind
&& !body_can_unwind
{
terminator.kind = TerminatorKind::UnwindTerminate(UnwindTerminateReason::Abi);
}

if block.is_cleanup {
continue;
}
let Some(terminator) = &block.terminator else { continue };
let span = terminator.source_info.span;

let call_can_unwind = match &terminator.kind {
TerminatorKind::Call { func, .. } => {
Expand Down Expand Up @@ -87,14 +96,18 @@ impl<'tcx> crate::MirPass<'tcx> for AbortUnwindingCalls {
if !call_can_unwind {
// If this function call can't unwind, then there's no need for it
// to have a landing pad. This means that we can remove any cleanup
// registered for it.
// registered for it (and turn it into `UnwindAction::Unreachable`).
let cleanup = block.terminator_mut().unwind_mut().unwrap();
*cleanup = UnwindAction::Unreachable;
} else if !body_can_unwind {
} else if !body_can_unwind
&& matches!(terminator.unwind(), Some(UnwindAction::Continue))
{
// Otherwise if this function can unwind, then if the outer function
// can also unwind there's nothing to do. If the outer function
// can't unwind, however, we need to change the landing pad for this
// function call to one that aborts.
// can't unwind, however, we need to ensure that any `UnwindAction::Continue`
// is replaced with terminate. For those with `UnwindAction::Cleanup`,
// cleanup will still happen, and terminate will happen afterwards handled by
// the `UnwindResume` -> `UnwindTerminate` terminator replacement.
let cleanup = block.terminator_mut().unwind_mut().unwrap();
*cleanup = UnwindAction::Terminate(UnwindTerminateReason::Abi);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,16 @@ fn main() -> () {
bb0: {
StorageLive(_1);
_1 = const ();
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind terminate(abi)];
asm!("", options(MAY_UNWIND)) -> [return: bb1, unwind: bb2];
}

bb1: {
StorageDead(_1);
_0 = const ();
return;
}

bb2 (cleanup): {
terminate(abi);
}
}
4 changes: 3 additions & 1 deletion tests/mir-opt/asm_unwind_panic_abort.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@
fn main() {
// CHECK-LABEL: fn main(
// CHECK: asm!(
// CHECK-SAME: unwind terminate(abi)
// CHECK-SAME: unwind: [[unwind:bb.*]]]
// CHECK: [[unwind]] (cleanup)
// CHECK-NEXT: terminate(abi)
unsafe {
std::arch::asm!("", options(may_unwind));
}
Expand Down
25 changes: 25 additions & 0 deletions tests/mir-opt/c_unwind_terminate.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//@ needs-unwind

struct Noise;
impl Drop for Noise {
fn drop(&mut self) {
eprintln!("Noisy Drop");
}
}

fn panic() {
panic!();
}

// EMIT_MIR c_unwind_terminate.test.AbortUnwindingCalls.after.mir
extern "C" fn test() {
// CHECK-LABEL: fn test(
// CHECK: drop
// CHECK-SAME: unwind: [[unwind:bb.*]]]
// CHECK: [[unwind]] (cleanup)
// CHECK-NEXT: terminate(abi)
let _val = Noise;
panic();
}

fn main() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// MIR for `test` after AbortUnwindingCalls

fn test() -> () {
let mut _0: ();
let _1: Noise;
let _2: ();
scope 1 {
debug _val => _1;
}

bb0: {
StorageLive(_1);
_1 = Noise;
StorageLive(_2);
_2 = panic() -> [return: bb1, unwind: bb3];
}

bb1: {
StorageDead(_2);
_0 = const ();
drop(_1) -> [return: bb2, unwind: bb4];
}

bb2: {
StorageDead(_1);
return;
}

bb3 (cleanup): {
drop(_1) -> [return: bb4, unwind terminate(cleanup)];
}

bb4 (cleanup): {
terminate(abi);
}
}
8 changes: 0 additions & 8 deletions tests/run-make/longjmp-across-rust/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,11 @@ fn main() {
}
}

struct A;

impl Drop for A {
fn drop(&mut self) {}
}

extern "C" fn test_middle() {
let _a = A;
foo();
}

fn foo() {
let _a = A;
unsafe {
test_end();
}
Expand Down
9 changes: 9 additions & 0 deletions tests/ui/panics/panic-in-ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,22 @@
//@ exec-env:RUST_BACKTRACE=0
//@ check-run-results
//@ error-pattern: panic in a function that cannot unwind
//@ error-pattern: Noisy Drop
//@ normalize-stderr-test: "\n +[0-9]+:[^\n]+" -> ""
//@ normalize-stderr-test: "\n +at [^\n]+" -> ""
//@ normalize-stderr-test: "(core/src/panicking\.rs):[0-9]+:[0-9]+" -> "$1:$$LINE:$$COL"
//@ needs-unwind
//@ ignore-emscripten "RuntimeError" junk in output

struct Noise;
impl Drop for Noise {
fn drop(&mut self) {
eprintln!("Noisy Drop");
}
}

extern "C" fn panic_in_ffi() {
let _val = Noise;
panic!("Test");
}

Expand Down
3 changes: 2 additions & 1 deletion tests/ui/panics/panic-in-ffi.run.stderr
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
thread 'main' panicked at $DIR/panic-in-ffi.rs:12:5:
thread 'main' panicked at $DIR/panic-in-ffi.rs:21:5:
Test
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Noisy Drop
thread 'main' panicked at core/src/panicking.rs:$LINE:$COL:
panic in a function that cannot unwind
stack backtrace:
Expand Down
Loading