Skip to content

Commit 486e208

Browse files
committed
Fix cross-DLL panics under MSVC
1 parent ed712e0 commit 486e208

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

src/doc/unstable-book/src/language-features/lang-items.md

-1
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,6 @@ the source code.
248248
- `eh_personality`: `libpanic_unwind/gcc.rs` (GNU)
249249
- `eh_personality`: `libpanic_unwind/seh.rs` (SEH)
250250
- `eh_unwind_resume`: `libpanic_unwind/gcc.rs` (GCC)
251-
- `eh_catch_typeinfo`: `libpanic_unwind/seh.rs` (SEH)
252251
- `eh_catch_typeinfo`: `libpanic_unwind/emcc.rs` (EMCC)
253252
- `panic`: `libcore/panicking.rs`
254253
- `panic_bounds_check`: `libcore/panicking.rs`

src/libpanic_unwind/seh.rs

+8-5
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,9 @@ pub struct _TypeDescriptor {
167167

168168
// Note that we intentionally ignore name mangling rules here: we don't want C++
169169
// to be able to catch Rust panics by simply declaring a `struct rust_panic`.
170+
//
171+
// When modifying, make sure that the type name string exactly matches
172+
// the one used in src/librustc_codegen_llvm/intrinsic.rs.
170173
const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
171174

172175
static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
@@ -199,12 +202,12 @@ extern "C" {
199202
static TYPE_INFO_VTABLE: *const u8;
200203
}
201204

202-
// We use #[lang = "eh_catch_typeinfo"] here as this is the type descriptor which
203-
// we'll use in LLVM's `catchpad` instruction which ends up also being passed as
204-
// an argument to the C++ personality function.
205+
// This type descriptor is only used when throwing an exception. The catch part
206+
// is handled by the try intrinsic, which generates its own TypeDescriptor.
205207
//
206-
// Again, I'm not entirely sure what this is describing, it just seems to work.
207-
#[cfg_attr(not(test), lang = "eh_catch_typeinfo")]
208+
// This is fine since the MSVC runtime uses string comparison on the type name
209+
// to match TypeDescriptors rather than pointer equality.
210+
#[cfg_attr(bootstrap, lang = "eh_catch_typeinfo")]
208211
static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
209212
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
210213
spare: core::ptr::null_mut(),

src/librustc_codegen_llvm/intrinsic.rs

+25-5
Original file line numberDiff line numberDiff line change
@@ -954,19 +954,39 @@ fn codegen_msvc_try(
954954
let cs = catchswitch.catch_switch(None, None, 1);
955955
catchswitch.add_handler(cs, catchpad.llbb());
956956

957+
// We can't use the TypeDescriptor defined in libpanic_unwind because it
958+
// might be in another DLL and the SEH encoding only supports specifying
959+
// a TypeDescriptor from the current module.
960+
//
961+
// However this isn't an issue since the MSVC runtime uses string
962+
// comparison on the type name to match TypeDescriptors rather than
963+
// pointer equality.
964+
//
965+
// So instead we generate a new TypeDescriptor in each module that uses
966+
// `try` and let the linker merge duplicate definitions in the same
967+
// module.
968+
//
969+
// When modifying, make sure that the type_name string exactly matches
970+
// the one used in src/libpanic_unwind/seh.rs.
971+
let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
972+
let type_name = bx.const_bytes(b"rust_panic\0");
973+
let type_info =
974+
bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
975+
let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
976+
unsafe {
977+
llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
978+
llvm::SetUniqueComdat(bx.llmod, tydesc);
979+
llvm::LLVMSetInitializer(tydesc, type_info);
980+
}
981+
957982
// The flag value of 8 indicates that we are catching the exception by
958983
// reference instead of by value. We can't use catch by value because
959984
// that requires copying the exception object, which we don't support
960985
// since our exception object effectively contains a Box.
961986
//
962987
// Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
963988
let flags = bx.const_i32(8);
964-
let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() {
965-
Some(did) => bx.get_static(did),
966-
None => bug!("eh_catch_typeinfo not defined, but needed for SEH unwinding"),
967-
};
968989
let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]);
969-
970990
let i64_align = bx.tcx().data_layout.i64_align.abi;
971991
let payload_ptr = catchpad.load(slot, ptr_align);
972992
let payload = catchpad.load(payload_ptr, i64_align);

0 commit comments

Comments
 (0)