Fix cross-DLL panics under MSVC
This commit is contained in:
parent
01d04944ce
commit
61b67d0c19
3 changed files with 33 additions and 11 deletions
|
@ -248,7 +248,6 @@ the source code.
|
|||
- `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
|
||||
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
|
||||
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
|
||||
- `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`
|
||||
|
|
|
@ -167,6 +167,9 @@ pub struct _TypeDescriptor {
|
|||
|
||||
// Note that we intentionally ignore name mangling rules here: we don't want C++
|
||||
// to be able to catch Rust panics by simply declaring a `struct rust_panic`.
|
||||
//
|
||||
// When modifying, make sure that the type name string exactly matches
|
||||
// the one used in src/librustc_codegen_llvm/intrinsic.rs.
|
||||
const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
|
||||
|
||||
static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
|
||||
|
@ -199,12 +202,12 @@ extern "C" {
|
|||
static TYPE_INFO_VTABLE: *const u8;
|
||||
}
|
||||
|
||||
// We use #[lang = "eh_catch_typeinfo"] here as this is the type descriptor which
|
||||
// we'll use in LLVM's `catchpad` instruction which ends up also being passed as
|
||||
// an argument to the C++ personality function.
|
||||
// This type descriptor is only used when throwing an exception. The catch part
|
||||
// is handled by the try intrinsic, which generates its own TypeDescriptor.
|
||||
//
|
||||
// Again, I'm not entirely sure what this is describing, it just seems to work.
|
||||
#[cfg_attr(not(test), lang = "eh_catch_typeinfo")]
|
||||
// This is fine since the MSVC runtime uses string comparison on the type name
|
||||
// to match TypeDescriptors rather than pointer equality.
|
||||
#[cfg_attr(bootstrap, lang = "eh_catch_typeinfo")]
|
||||
static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
|
||||
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
|
||||
spare: core::ptr::null_mut(),
|
||||
|
|
|
@ -954,6 +954,31 @@ fn codegen_msvc_try(
|
|||
let cs = catchswitch.catch_switch(None, None, 1);
|
||||
catchswitch.add_handler(cs, catchpad.llbb());
|
||||
|
||||
// We can't use the TypeDescriptor defined in libpanic_unwind because it
|
||||
// might be in another DLL and the SEH encoding only supports specifying
|
||||
// a TypeDescriptor from the current module.
|
||||
//
|
||||
// However this isn't an issue since the MSVC runtime uses string
|
||||
// comparison on the type name to match TypeDescriptors rather than
|
||||
// pointer equality.
|
||||
//
|
||||
// So instead we generate a new TypeDescriptor in each module that uses
|
||||
// `try` and let the linker merge duplicate definitions in the same
|
||||
// module.
|
||||
//
|
||||
// When modifying, make sure that the type_name string exactly matches
|
||||
// the one used in src/libpanic_unwind/seh.rs.
|
||||
let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
|
||||
let type_name = bx.const_bytes(b"rust_panic\0");
|
||||
let type_info =
|
||||
bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
|
||||
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
|
||||
unsafe {
|
||||
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
|
||||
llvm::SetUniqueComdat(bx.llmod, tydesc);
|
||||
llvm::LLVMSetInitializer(tydesc, type_info);
|
||||
}
|
||||
|
||||
// The flag value of 8 indicates that we are catching the exception by
|
||||
// reference instead of by value. We can't use catch by value because
|
||||
// that requires copying the exception object, which we don't support
|
||||
|
@ -961,12 +986,7 @@ fn codegen_msvc_try(
|
|||
//
|
||||
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
|
||||
let flags = bx.const_i32(8);
|
||||
let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() {
|
||||
Some(did) => bx.get_static(did),
|
||||
None => bug!("eh_catch_typeinfo not defined, but needed for SEH unwinding"),
|
||||
};
|
||||
let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]);
|
||||
|
||||
let i64_align = bx.tcx().data_layout.i64_align.abi;
|
||||
let payload_ptr = catchpad.load(slot, ptr_align);
|
||||
let payload = catchpad.load(payload_ptr, i64_align);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue