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

Allow foreign exceptions to unwind through Rust code and Rust panics to unwind through FFI #65646

Merged
merged 7 commits into from
Nov 3, 2019
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
6 changes: 3 additions & 3 deletions src/doc/unstable-book/src/language-features/lang-items.md
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,11 @@ the source code.
- Runtime
- `start`: `libstd/rt.rs`
- `eh_personality`: `libpanic_unwind/emcc.rs` (EMCC)
- `eh_personality`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
- `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
- `eh_unwind_resume`: `libpanic_unwind/seh64_gnu.rs` (SEH64 GNU)
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
- `msvc_try_filter`: `libpanic_unwind/seh.rs` (SEH)
- `eh_catch_typeinfo`: `libpanic_unwind/seh.rs` (SEH)
- `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)
- `panic`: `libcore/panicking.rs`
- `panic_bounds_check`: `libcore/panicking.rs`
- `panic_impl`: `libcore/panicking.rs`
Expand Down
15 changes: 11 additions & 4 deletions src/libpanic_unwind/dwarf/eh.rs
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ pub enum EHAction {

pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm"));

pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>, foreign_exception: bool)
-> Result<EHAction, ()>
{
if lsda.is_null() {
Expand Down Expand Up @@ -96,7 +96,7 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
return Ok(EHAction::None)
} else {
let lpad = lpad_base + cs_lpad;
return Ok(interpret_cs_action(cs_action, lpad))
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
}
}
}
Expand All @@ -121,16 +121,23 @@ pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>)
// Can never have null landing pad for sjlj -- that would have
// been indicated by a -1 call site index.
let lpad = (cs_lpad + 1) as usize;
return Ok(interpret_cs_action(cs_action, lpad))
return Ok(interpret_cs_action(cs_action, lpad, foreign_exception))
}
}
}
}

fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction {
fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction {
if cs_action == 0 {
// If cs_action is 0 then this is a cleanup (Drop::drop). We run these
// for both Rust panics and foriegn exceptions.
EHAction::Cleanup(lpad)
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
} else if foreign_exception {
// catch_unwind should not catch foreign exceptions, only Rust panics.
// Instead just continue unwinding.
EHAction::None
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
} else {
// Stop unwinding Rust panics at catch_unwind.
EHAction::Catch(lpad)
nikomatsakis marked this conversation as resolved.
Show resolved Hide resolved
}
}
Expand Down
52 changes: 42 additions & 10 deletions src/libpanic_unwind/emcc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,48 @@ use alloc::boxed::Box;
use libc::{self, c_int};
use unwind as uw;

// This matches the layout of std::type_info in C++
#[repr(C)]
struct TypeInfo {
vtable: *const usize,
name: *const u8,
}
unsafe impl Sync for TypeInfo {}

extern "C" {
// The leading `\x01` byte here is actually a magical signal to LLVM to
// *not* apply any other mangling like prefixing with a `_` character.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wow, powerful magic :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's probably not even necessary here, I just copied it from seh.rs.

//
// This symbol is the vtable used by C++'s `std::type_info`. Objects of type
// `std::type_info`, type descriptors, have a pointer to this table. Type
// descriptors are referenced by the C++ EH structures defined above and
// that we construct below.
//
// Note that the real size is larger than 3 usize, but we only need our
// vtable to point to the third element.
#[link_name = "\x01_ZTVN10__cxxabiv117__class_type_infoE"]
static CLASS_TYPE_INFO_VTABLE: [usize; 3];
alexcrichton marked this conversation as resolved.
Show resolved Hide resolved
}

// std::type_info for a rust_panic class
#[lang = "eh_catch_typeinfo"]
static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo {
// Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
vtable: unsafe { &CLASS_TYPE_INFO_VTABLE[2] },
// This intentionally doesn't use the normal name mangling scheme because
// we don't want C++ to be able to produce or catch Rust panics.
name: b"rust_panic\0".as_ptr(),
};

pub fn payload() -> *mut u8 {
ptr::null_mut()
}

pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
assert!(!ptr.is_null());
let ex = ptr::read(ptr as *mut _);
__cxa_free_exception(ptr as *mut _);
let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void);
let ex = ptr::read(adjusted_ptr as *mut _);
__cxa_end_catch();
ex
}

Expand All @@ -32,11 +66,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
if exception == ptr::null_mut() {
return uw::_URC_FATAL_PHASE1_ERROR as u32;
}
let exception = exception as *mut Box<dyn Any + Send>;
ptr::write(exception, data);
__cxa_throw(exception as *mut _, ptr::null_mut(), ptr::null_mut());

unreachable!()
ptr::write(exception as *mut _, data);
__cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, ptr::null_mut());
}

#[lang = "eh_personality"]
Expand All @@ -52,10 +83,11 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,

extern "C" {
fn __cxa_allocate_exception(thrown_size: libc::size_t) -> *mut libc::c_void;
fn __cxa_free_exception(thrown_exception: *mut libc::c_void);
fn __cxa_begin_catch(thrown_exception: *mut libc::c_void) -> *mut libc::c_void;
fn __cxa_end_catch();
fn __cxa_throw(thrown_exception: *mut libc::c_void,
tinfo: *mut libc::c_void,
dest: *mut libc::c_void);
tinfo: *const TypeInfo,
dest: *mut libc::c_void) -> !;
fn __gxx_personality_v0(version: c_int,
actions: uw::_Unwind_Action,
exception_class: uw::_Unwind_Exception_Class,
Expand Down
Loading