1
Fork 0

Fix cross-DLL panics under MSVC

This commit is contained in:
Amanieu d'Antras 2020-01-13 00:55:36 +00:00
parent 01d04944ce
commit 61b67d0c19
3 changed files with 33 additions and 11 deletions

View file

@ -248,7 +248,6 @@ the source code.
- `eh_personality`: `libpanic_unwind/gcc.rs` (GNU) - `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH) - `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC) - `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
- `eh_catch_typeinfo`: `libpanic_unwind/seh.rs` (SEH)
- `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC) - `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)
- `panic`: `libcore/panicking.rs` - `panic`: `libcore/panicking.rs`
- `panic_bounds_check`: `libcore/panicking.rs` - `panic_bounds_check`: `libcore/panicking.rs`

View file

@ -167,6 +167,9 @@ pub struct _TypeDescriptor {
// Note that we intentionally ignore name mangling rules here: we don't want C++ // 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`. // 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"; const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
static mut THROW_INFO: _ThrowInfo = _ThrowInfo { static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
@ -199,12 +202,12 @@ extern "C" {
static TYPE_INFO_VTABLE: *const u8; static TYPE_INFO_VTABLE: *const u8;
} }
// We use #[lang = "eh_catch_typeinfo"] here as this is the type descriptor which // This type descriptor is only used when throwing an exception. The catch part
// we'll use in LLVM's `catchpad` instruction which ends up also being passed as // is handled by the try intrinsic, which generates its own TypeDescriptor.
// an argument to the C++ personality function.
// //
// Again, I'm not entirely sure what this is describing, it just seems to work. // This is fine since the MSVC runtime uses string comparison on the type name
#[cfg_attr(not(test), lang = "eh_catch_typeinfo")] // to match TypeDescriptors rather than pointer equality.
#[cfg_attr(bootstrap, lang = "eh_catch_typeinfo")]
static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
spare: core::ptr::null_mut(), spare: core::ptr::null_mut(),

View file

@ -954,6 +954,31 @@ fn codegen_msvc_try(
let cs = catchswitch.catch_switch(None, None, 1); let cs = catchswitch.catch_switch(None, None, 1);
catchswitch.add_handler(cs, catchpad.llbb()); 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 // 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 // reference instead of by value. We can't use catch by value because
// that requires copying the exception object, which we don't support // that requires copying the exception object, which we don't support
@ -961,12 +986,7 @@ fn codegen_msvc_try(
// //
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
let flags = bx.const_i32(8); 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 funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]);
let i64_align = bx.tcx().data_layout.i64_align.abi; let i64_align = bx.tcx().data_layout.i64_align.abi;
let payload_ptr = catchpad.load(slot, ptr_align); let payload_ptr = catchpad.load(slot, ptr_align);
let payload = catchpad.load(payload_ptr, i64_align); let payload = catchpad.load(payload_ptr, i64_align);