diff --git a/src/libpanic_unwind/lib.rs b/src/libpanic_unwind/lib.rs index 50d067b56e44..d2a0ef7b1dde 100644 --- a/src/libpanic_unwind/lib.rs +++ b/src/libpanic_unwind/lib.rs @@ -61,7 +61,6 @@ cfg_if::cfg_if! { } mod dwarf; -mod windows; // Entry point for catching an exception, implemented using the `try` intrinsic // in the compiler. diff --git a/src/libpanic_unwind/seh.rs b/src/libpanic_unwind/seh.rs index 809e4619812d..9e76b92a7d74 100644 --- a/src/libpanic_unwind/seh.rs +++ b/src/libpanic_unwind/seh.rs @@ -51,9 +51,7 @@ use alloc::boxed::Box; use core::any::Any; use core::mem; use core::raw; - -use crate::windows as c; -use libc::{c_int, c_uint}; +use libc::{c_int, c_uint, c_void}; // First up, a whole bunch of type definitions. There's a few platform-specific // oddities here, and a lot that's just blatantly copied from LLVM. The purpose @@ -76,18 +74,19 @@ use libc::{c_int, c_uint}; // sort of operation. For example, if you compile this C++ code on MSVC and emit // the LLVM IR: // -// #include +// #include +// +// struct rust_panic { +// uint64_t x[2]; +// } // // void foo() { -// uint64_t a[2] = {0, 1}; +// rust_panic a = {0, 1}; // throw a; // } // // That's essentially what we're trying to emulate. Most of the constant values -// below were just copied from LLVM, I'm at least not 100% sure what's going on -// everywhere. For example the `.PA_K\0` and `.PEA_K\0` strings below (stuck in -// the names of a few of these) I'm not actually sure what they do, but it seems -// to mirror what LLVM does! +// below were just copied from LLVM, // // In any case, these structures are all constructed in a similar manner, and // it's just somewhat verbose for us. @@ -98,10 +97,9 @@ use libc::{c_int, c_uint}; #[macro_use] mod imp { pub type ptr_t = *mut u8; - pub const OFFSET: i32 = 4; + #[cfg(bootstrap)] pub const NAME1: [u8; 7] = [b'.', b'P', b'A', b'_', b'K', 0, 0]; - pub const NAME2: [u8; 7] = [b'.', b'P', b'A', b'X', 0, 0, 0]; macro_rules! ptr { (0) => (core::ptr::null_mut()); @@ -113,10 +111,9 @@ mod imp { #[macro_use] mod imp { pub type ptr_t = u32; - pub const OFFSET: i32 = 8; + #[cfg(bootstrap)] pub const NAME1: [u8; 7] = [b'.', b'P', b'E', b'A', b'_', b'K', 0]; - pub const NAME2: [u8; 7] = [b'.', b'P', b'E', b'A', b'X', 0, 0]; extern "C" { pub static __ImageBase: u8; @@ -141,7 +138,7 @@ pub struct _ThrowInfo { #[repr(C)] pub struct _CatchableTypeArray { pub nCatchableTypes: c_int, - pub arrayOfCatchableTypes: [imp::ptr_t; 2], + pub arrayOfCatchableTypes: [imp::ptr_t; 1], } #[repr(C)] @@ -164,9 +161,19 @@ pub struct _PMD { pub struct _TypeDescriptor { pub pVFTable: *const u8, pub spare: *mut u8, + #[cfg(bootstrap)] pub name: [u8; 7], + #[cfg(not(bootstrap))] + pub name: [u8; 11], } +// 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`. +#[cfg(bootstrap)] +use imp::NAME1 as TYPE_NAME; +#[cfg(not(bootstrap))] +const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; + static mut THROW_INFO: _ThrowInfo = _ThrowInfo { attributes: 0, pnfnUnwind: ptr!(0), @@ -175,31 +182,22 @@ static mut THROW_INFO: _ThrowInfo = _ThrowInfo { }; static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray { - nCatchableTypes: 2, - arrayOfCatchableTypes: [ptr!(0), ptr!(0)], + nCatchableTypes: 1, + arrayOfCatchableTypes: [ptr!(0)], }; -static mut CATCHABLE_TYPE1: _CatchableType = _CatchableType { - properties: 1, +static mut CATCHABLE_TYPE: _CatchableType = _CatchableType { + properties: 0, pType: ptr!(0), thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0, }, - sizeOrOffset: imp::OFFSET, - copy_function: ptr!(0), -}; - -static mut CATCHABLE_TYPE2: _CatchableType = _CatchableType { - properties: 1, - pType: ptr!(0), - thisDisplacement: _PMD { - mdisp: 0, - pdisp: -1, - vdisp: 0, - }, - sizeOrOffset: imp::OFFSET, + #[cfg(bootstrap)] + sizeOrOffset: mem::size_of::<*mut u64>() as c_int, + #[cfg(not(bootstrap))] + sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int, copy_function: ptr!(0), }; @@ -221,16 +219,10 @@ extern "C" { // // Again, I'm not entirely sure what this is describing, it just seems to work. #[cfg_attr(not(test), lang = "msvc_try_filter")] -static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor { +static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, spare: core::ptr::null_mut(), - name: imp::NAME1, -}; - -static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor { - pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _, - spare: core::ptr::null_mut(), - name: imp::NAME2, + name: TYPE_NAME, }; pub unsafe fn panic(data: Box) -> u32 { @@ -246,6 +238,11 @@ pub unsafe fn panic(data: Box) -> u32 { let ptrs = mem::transmute::<_, raw::TraitObject>(data); let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64]; let mut ptrs_ptr = ptrs.as_mut_ptr(); + let throw_ptr = if cfg!(bootstrap) { + &mut ptrs_ptr as *mut _ as *mut _ + } else { + ptrs_ptr as *mut _ + }; // This... may seems surprising, and justifiably so. On 32-bit MSVC the // pointers between these structure are just that, pointers. On 64-bit MSVC, @@ -270,17 +267,17 @@ pub unsafe fn panic(data: Box) -> u32 { atomic_store(&mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32, ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32); atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32, - ptr!(&CATCHABLE_TYPE1 as *const _) as u32); - atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[1] as *mut _ as *mut u32, - ptr!(&CATCHABLE_TYPE2 as *const _) as u32); - atomic_store(&mut CATCHABLE_TYPE1.pType as *mut _ as *mut u32, - ptr!(&TYPE_DESCRIPTOR1 as *const _) as u32); - atomic_store(&mut CATCHABLE_TYPE2.pType as *mut _ as *mut u32, - ptr!(&TYPE_DESCRIPTOR2 as *const _) as u32); + ptr!(&CATCHABLE_TYPE as *const _) as u32); + atomic_store(&mut CATCHABLE_TYPE.pType as *mut _ as *mut u32, + ptr!(&TYPE_DESCRIPTOR as *const _) as u32); - c::_CxxThrowException(&mut ptrs_ptr as *mut _ as *mut _, - &mut THROW_INFO as *mut _ as *mut _); - u32::max_value() + extern "system" { + #[unwind(allowed)] + pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; + } + + _CxxThrowException(throw_ptr, + &mut THROW_INFO as *mut _ as *mut _); } pub fn payload() -> [u64; 2] { diff --git a/src/libpanic_unwind/windows.rs b/src/libpanic_unwind/windows.rs deleted file mode 100644 index 3257a9d25a51..000000000000 --- a/src/libpanic_unwind/windows.rs +++ /dev/null @@ -1,86 +0,0 @@ -#![allow(nonstandard_style)] -#![allow(dead_code)] -#![cfg(windows)] - -use libc::{c_long, c_ulong, c_void}; - -pub type DWORD = c_ulong; -pub type LONG = c_long; -pub type ULONG_PTR = usize; -pub type LPVOID = *mut c_void; - -pub const EXCEPTION_MAXIMUM_PARAMETERS: usize = 15; -pub const EXCEPTION_NONCONTINUABLE: DWORD = 0x1; // Noncontinuable exception -pub const EXCEPTION_UNWINDING: DWORD = 0x2; // Unwind is in progress -pub const EXCEPTION_EXIT_UNWIND: DWORD = 0x4; // Exit unwind is in progress -pub const EXCEPTION_TARGET_UNWIND: DWORD = 0x20; // Target unwind in progress -pub const EXCEPTION_COLLIDED_UNWIND: DWORD = 0x40; // Collided exception handler call -pub const EXCEPTION_UNWIND: DWORD = EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND | - EXCEPTION_TARGET_UNWIND | - EXCEPTION_COLLIDED_UNWIND; - -#[repr(C)] -pub struct EXCEPTION_RECORD { - pub ExceptionCode: DWORD, - pub ExceptionFlags: DWORD, - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ExceptionAddress: LPVOID, - pub NumberParameters: DWORD, - pub ExceptionInformation: [LPVOID; EXCEPTION_MAXIMUM_PARAMETERS], -} - -#[repr(C)] -pub struct EXCEPTION_POINTERS { - pub ExceptionRecord: *mut EXCEPTION_RECORD, - pub ContextRecord: *mut CONTEXT, -} - -pub enum UNWIND_HISTORY_TABLE {} - -#[repr(C)] -pub struct RUNTIME_FUNCTION { - pub BeginAddress: DWORD, - pub EndAddress: DWORD, - pub UnwindData: DWORD, -} - -pub enum CONTEXT {} - -#[repr(C)] -pub struct DISPATCHER_CONTEXT { - pub ControlPc: LPVOID, - pub ImageBase: LPVOID, - pub FunctionEntry: *const RUNTIME_FUNCTION, - pub EstablisherFrame: LPVOID, - pub TargetIp: LPVOID, - pub ContextRecord: *const CONTEXT, - pub LanguageHandler: LPVOID, - pub HandlerData: *const u8, - pub HistoryTable: *const UNWIND_HISTORY_TABLE, -} - -#[repr(C)] -pub enum EXCEPTION_DISPOSITION { - ExceptionContinueExecution, - ExceptionContinueSearch, - ExceptionNestedException, - ExceptionCollidedUnwind, -} -pub use self::EXCEPTION_DISPOSITION::*; - -extern "system" { - #[unwind(allowed)] - pub fn RaiseException(dwExceptionCode: DWORD, - dwExceptionFlags: DWORD, - nNumberOfArguments: DWORD, - lpArguments: *const ULONG_PTR); - #[unwind(allowed)] - pub fn RtlUnwindEx(TargetFrame: LPVOID, - TargetIp: LPVOID, - ExceptionRecord: *const EXCEPTION_RECORD, - ReturnValue: LPVOID, - OriginalContext: *const CONTEXT, - HistoryTable: *const UNWIND_HISTORY_TABLE); - #[unwind(allowed)] - pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8); -} diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs index 97bd57a7ded0..efebac557593 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/src/librustc_codegen_llvm/intrinsic.rs @@ -849,7 +849,7 @@ fn codegen_msvc_try( // We're generating an IR snippet that looks like: // // declare i32 @rust_try(%func, %data, %ptr) { - // %slot = alloca i64* + // %slot = alloca [2 x i64] // invoke %func(%data) to label %normal unwind label %catchswitch // // normal: @@ -873,21 +873,25 @@ fn codegen_msvc_try( // // #include // + // struct rust_panic { + // uint64_t x[2]; + // } + // // int bar(void (*foo)(void), uint64_t *ret) { // try { // foo(); // return 0; - // } catch(uint64_t a[2]) { - // ret[0] = a[0]; - // ret[1] = a[1]; + // } catch(rust_panic a) { + // ret[0] = a.x[0]; + // ret[1] = a.x[1]; // return 1; // } // } // // More information can be found in libstd's seh.rs implementation. - let i64p = bx.type_ptr_to(bx.type_i64()); - let ptr_align = bx.tcx().data_layout.pointer_align.abi; - let slot = bx.alloca(i64p, ptr_align); + let i64_2 = bx.type_array(bx.type_i64(), 2); + let i64_align = bx.tcx().data_layout.i64_align.abi; + let slot = bx.alloca(i64_2, i64_align); bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); normal.ret(bx.const_i32(0)); @@ -900,17 +904,10 @@ fn codegen_msvc_try( None => bug!("msvc_try_filter not defined"), }; let funclet = catchpad.catch_pad(cs, &[tydesc, bx.const_i32(0), slot]); - let addr = catchpad.load(slot, ptr_align); - let i64_align = bx.tcx().data_layout.i64_align.abi; - let arg1 = catchpad.load(addr, i64_align); - let val1 = bx.const_i32(1); - let gep1 = catchpad.inbounds_gep(addr, &[val1]); - let arg2 = catchpad.load(gep1, i64_align); - let local_ptr = catchpad.bitcast(local_ptr, i64p); - let gep2 = catchpad.inbounds_gep(local_ptr, &[val1]); - catchpad.store(arg1, local_ptr, i64_align); - catchpad.store(arg2, gep2, i64_align); + let payload = catchpad.load(slot, i64_align); + let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2)); + catchpad.store(payload, local_ptr, i64_align); catchpad.catch_ret(&funclet, caught.llbb()); caught.ret(bx.const_i32(1)); diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp index 9a6fab49f496..b0fd65f88e7d 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp @@ -8,6 +8,7 @@ void println(const char* s) { } struct exception {}; +struct rust_panic {}; struct drop_check { bool* ok; @@ -45,7 +46,7 @@ extern "C" { x.ok = NULL; try { cb(); - } catch (exception e) { + } catch (rust_panic e) { assert(false && "shouldn't be able to catch a rust panic"); } catch (...) { println("caught foreign exception in catch (...)");