Skip to content

Commit

Permalink
Abort if C++ tries to swallow a Rust panic
Browse files Browse the repository at this point in the history
  • Loading branch information
Amanieu committed Jan 11, 2020
1 parent 757ed07 commit 3a02576
Show file tree
Hide file tree
Showing 7 changed files with 17 additions and 46 deletions.
1 change: 1 addition & 0 deletions src/libpanic_unwind/emcc.rs
Expand Up @@ -80,6 +80,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
extern "C" fn exception_cleanup(ptr: *mut libc::c_void) {
unsafe {
ptr::drop_in_place(ptr as *mut Exception);
super::__rust_drop_panic();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions src/libpanic_unwind/gcc.rs
Expand Up @@ -78,6 +78,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
) {
unsafe {
let _: Box<Exception> = Box::from_raw(exception as *mut Exception);
super::__rust_drop_panic();
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions src/libpanic_unwind/lib.rs
Expand Up @@ -61,6 +61,12 @@ cfg_if::cfg_if! {
}
}

extern "C" {
/// Handler in libstd called when a panic object is dropped outside of
/// `catch_unwind`.
fn __rust_drop_panic() -> !;
}

mod dwarf;

// Entry point for catching an exception, implemented using the `try` intrinsic
Expand Down
1 change: 1 addition & 0 deletions src/libpanic_unwind/seh.rs
Expand Up @@ -229,6 +229,7 @@ macro_rules! define_cleanup {
unsafe extern $abi fn exception_cleanup(e: *mut [u64; 2]) {
if (*e)[0] != 0 {
cleanup(*e);
super::__rust_drop_panic();
}
}
#[unwind(allowed)]
Expand Down
8 changes: 8 additions & 0 deletions src/libstd/panicking.rs
Expand Up @@ -55,6 +55,14 @@ extern "C" {
fn __rust_start_panic(payload: usize) -> u32;
}

/// This function is called by the panic runtime if FFI code catches a Rust
/// panic but doesn't rethrow it. We don't support this case since it messes
/// with our panic count.
#[rustc_std_internal_symbol]
extern "C" fn __rust_drop_panic() -> ! {
rtabort!("Rust panics must be rethrown");
}

#[derive(Copy, Clone)]
enum Hook {
Default,
Expand Down
17 changes: 0 additions & 17 deletions src/test/run-make-fulldeps/foreign-exceptions/foo.cpp
Expand Up @@ -57,21 +57,4 @@ extern "C" {
throw;
}
}

void swallow_exception(void (*cb)()) {
try {
// Do a rethrow to ensure that the exception is only dropped once.
// This is necessary since we don't support copying exceptions.
try {
cb();
} catch (...) {
println("rethrowing Rust panic");
throw;
};
} catch (rust_panic e) {
assert(false && "shouldn't be able to catch a rust panic");
} catch (...) {
println("swallowing foreign exception in catch (...)");
}
}
}
29 changes: 0 additions & 29 deletions src/test/run-make-fulldeps/foreign-exceptions/foo.rs
Expand Up @@ -19,8 +19,6 @@ impl<'a> Drop for DropCheck<'a> {
extern "C" {
fn throw_cxx_exception();

fn swallow_exception(cb: extern "C" fn());

#[unwind(allowed)]
fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool);
}
Expand Down Expand Up @@ -61,34 +59,7 @@ fn throw_rust_panic() {
assert!(cxx_ok);
}

fn check_exception_drop() {
static mut DROP_COUNT: usize = 0;

struct CountDrop;
impl Drop for CountDrop {
fn drop(&mut self) {
println!("CountDrop::drop");
unsafe {
DROP_COUNT += 1;
}
}
}


#[unwind(allowed)]
extern "C" fn callback() {
println!("throwing rust panic #2");
panic!(CountDrop);
}

unsafe {
swallow_exception(callback);
assert_eq!(DROP_COUNT, 1);
}
}

fn main() {
unsafe { throw_cxx_exception() };
throw_rust_panic();
check_exception_drop();
}

0 comments on commit 3a02576

Please sign in to comment.