1
Fork 0

Make SEH exceptions use a rust_panic type instead of unsigned __int64*

This commit is contained in:
Amanieu d'Antras 2019-10-27 22:33:25 +00:00
parent 83d6bf4929
commit ad61c88e72
5 changed files with 62 additions and 154 deletions

View file

@ -61,7 +61,6 @@ cfg_if::cfg_if! {
} }
mod dwarf; mod dwarf;
mod windows;
// Entry point for catching an exception, implemented using the `try` intrinsic // Entry point for catching an exception, implemented using the `try` intrinsic
// in the compiler. // in the compiler.

View file

@ -51,9 +51,7 @@ use alloc::boxed::Box;
use core::any::Any; use core::any::Any;
use core::mem; use core::mem;
use core::raw; use core::raw;
use libc::{c_int, c_uint, c_void};
use crate::windows as c;
use libc::{c_int, c_uint};
// First up, a whole bunch of type definitions. There's a few platform-specific // 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 // 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 // sort of operation. For example, if you compile this C++ code on MSVC and emit
// the LLVM IR: // the LLVM IR:
// //
// #include <stdin.h> // #include <stdint.h>
//
// struct rust_panic {
// uint64_t x[2];
// }
// //
// void foo() { // void foo() {
// uint64_t a[2] = {0, 1}; // rust_panic a = {0, 1};
// throw a; // throw a;
// } // }
// //
// That's essentially what we're trying to emulate. Most of the constant values // 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 // below were just copied from LLVM,
// 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!
// //
// In any case, these structures are all constructed in a similar manner, and // In any case, these structures are all constructed in a similar manner, and
// it's just somewhat verbose for us. // it's just somewhat verbose for us.
@ -98,10 +97,9 @@ use libc::{c_int, c_uint};
#[macro_use] #[macro_use]
mod imp { mod imp {
pub type ptr_t = *mut u8; 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 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 { macro_rules! ptr {
(0) => (core::ptr::null_mut()); (0) => (core::ptr::null_mut());
@ -113,10 +111,9 @@ mod imp {
#[macro_use] #[macro_use]
mod imp { mod imp {
pub type ptr_t = u32; 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 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" { extern "C" {
pub static __ImageBase: u8; pub static __ImageBase: u8;
@ -141,7 +138,7 @@ pub struct _ThrowInfo {
#[repr(C)] #[repr(C)]
pub struct _CatchableTypeArray { pub struct _CatchableTypeArray {
pub nCatchableTypes: c_int, pub nCatchableTypes: c_int,
pub arrayOfCatchableTypes: [imp::ptr_t; 2], pub arrayOfCatchableTypes: [imp::ptr_t; 1],
} }
#[repr(C)] #[repr(C)]
@ -164,9 +161,19 @@ pub struct _PMD {
pub struct _TypeDescriptor { pub struct _TypeDescriptor {
pub pVFTable: *const u8, pub pVFTable: *const u8,
pub spare: *mut u8, pub spare: *mut u8,
#[cfg(bootstrap)]
pub name: [u8; 7], 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 { static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
attributes: 0, attributes: 0,
pnfnUnwind: ptr!(0), pnfnUnwind: ptr!(0),
@ -175,31 +182,22 @@ static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
}; };
static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray { static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray {
nCatchableTypes: 2, nCatchableTypes: 1,
arrayOfCatchableTypes: [ptr!(0), ptr!(0)], arrayOfCatchableTypes: [ptr!(0)],
}; };
static mut CATCHABLE_TYPE1: _CatchableType = _CatchableType { static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
properties: 1, properties: 0,
pType: ptr!(0), pType: ptr!(0),
thisDisplacement: _PMD { thisDisplacement: _PMD {
mdisp: 0, mdisp: 0,
pdisp: -1, pdisp: -1,
vdisp: 0, vdisp: 0,
}, },
sizeOrOffset: imp::OFFSET, #[cfg(bootstrap)]
copy_function: ptr!(0), sizeOrOffset: mem::size_of::<*mut u64>() as c_int,
}; #[cfg(not(bootstrap))]
sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
static mut CATCHABLE_TYPE2: _CatchableType = _CatchableType {
properties: 1,
pType: ptr!(0),
thisDisplacement: _PMD {
mdisp: 0,
pdisp: -1,
vdisp: 0,
},
sizeOrOffset: imp::OFFSET,
copy_function: ptr!(0), 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. // Again, I'm not entirely sure what this is describing, it just seems to work.
#[cfg_attr(not(test), lang = "msvc_try_filter")] #[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 _, pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
spare: core::ptr::null_mut(), spare: core::ptr::null_mut(),
name: imp::NAME1, name: TYPE_NAME,
};
static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor {
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
spare: core::ptr::null_mut(),
name: imp::NAME2,
}; };
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
@ -246,6 +238,11 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
let ptrs = mem::transmute::<_, raw::TraitObject>(data); let ptrs = mem::transmute::<_, raw::TraitObject>(data);
let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64]; let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
let mut ptrs_ptr = ptrs.as_mut_ptr(); 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 // This... may seems surprising, and justifiably so. On 32-bit MSVC the
// pointers between these structure are just that, pointers. On 64-bit MSVC, // pointers between these structure are just that, pointers. On 64-bit MSVC,
@ -270,17 +267,17 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
atomic_store(&mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32, atomic_store(&mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32,
ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32); ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32);
atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32, atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32,
ptr!(&CATCHABLE_TYPE1 as *const _) as u32); ptr!(&CATCHABLE_TYPE as *const _) as u32);
atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[1] as *mut _ as *mut u32, atomic_store(&mut CATCHABLE_TYPE.pType as *mut _ as *mut u32,
ptr!(&CATCHABLE_TYPE2 as *const _) as u32); ptr!(&TYPE_DESCRIPTOR 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);
c::_CxxThrowException(&mut ptrs_ptr as *mut _ as *mut _, extern "system" {
&mut THROW_INFO as *mut _ as *mut _); #[unwind(allowed)]
u32::max_value() 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] { pub fn payload() -> [u64; 2] {

View file

@ -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);
}

View file

@ -849,7 +849,7 @@ fn codegen_msvc_try(
// We're generating an IR snippet that looks like: // We're generating an IR snippet that looks like:
// //
// declare i32 @rust_try(%func, %data, %ptr) { // declare i32 @rust_try(%func, %data, %ptr) {
// %slot = alloca i64* // %slot = alloca [2 x i64]
// invoke %func(%data) to label %normal unwind label %catchswitch // invoke %func(%data) to label %normal unwind label %catchswitch
// //
// normal: // normal:
@ -873,21 +873,25 @@ fn codegen_msvc_try(
// //
// #include <stdint.h> // #include <stdint.h>
// //
// struct rust_panic {
// uint64_t x[2];
// }
//
// int bar(void (*foo)(void), uint64_t *ret) { // int bar(void (*foo)(void), uint64_t *ret) {
// try { // try {
// foo(); // foo();
// return 0; // return 0;
// } catch(uint64_t a[2]) { // } catch(rust_panic a) {
// ret[0] = a[0]; // ret[0] = a.x[0];
// ret[1] = a[1]; // ret[1] = a.x[1];
// return 1; // return 1;
// } // }
// } // }
// //
// More information can be found in libstd's seh.rs implementation. // More information can be found in libstd's seh.rs implementation.
let i64p = bx.type_ptr_to(bx.type_i64()); let i64_2 = bx.type_array(bx.type_i64(), 2);
let ptr_align = bx.tcx().data_layout.pointer_align.abi; let i64_align = bx.tcx().data_layout.i64_align.abi;
let slot = bx.alloca(i64p, ptr_align); let slot = bx.alloca(i64_2, i64_align);
bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None); bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
normal.ret(bx.const_i32(0)); normal.ret(bx.const_i32(0));
@ -900,17 +904,10 @@ fn codegen_msvc_try(
None => bug!("msvc_try_filter not defined"), None => bug!("msvc_try_filter not defined"),
}; };
let funclet = catchpad.catch_pad(cs, &[tydesc, bx.const_i32(0), slot]); 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 payload = catchpad.load(slot, i64_align);
let arg1 = catchpad.load(addr, i64_align); let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2));
let val1 = bx.const_i32(1); catchpad.store(payload, local_ptr, i64_align);
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);
catchpad.catch_ret(&funclet, caught.llbb()); catchpad.catch_ret(&funclet, caught.llbb());
caught.ret(bx.const_i32(1)); caught.ret(bx.const_i32(1));

View file

@ -8,6 +8,7 @@ void println(const char* s) {
} }
struct exception {}; struct exception {};
struct rust_panic {};
struct drop_check { struct drop_check {
bool* ok; bool* ok;
@ -45,7 +46,7 @@ extern "C" {
x.ok = NULL; x.ok = NULL;
try { try {
cb(); cb();
} catch (exception e) { } catch (rust_panic e) {
assert(false && "shouldn't be able to catch a rust panic"); assert(false && "shouldn't be able to catch a rust panic");
} catch (...) { } catch (...) {
println("caught foreign exception in catch (...)"); println("caught foreign exception in catch (...)");