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/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`
|
||||||
|
|
|
@ -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(),
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue