Skip to content

Commit ad61c88

Browse files
committed
Make SEH exceptions use a rust_panic type instead of unsigned __int64*
1 parent 83d6bf4 commit ad61c88

File tree

5 files changed

+62
-154
lines changed

5 files changed

+62
-154
lines changed

src/libpanic_unwind/lib.rs

-1
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,6 @@ cfg_if::cfg_if! {
6161
}
6262

6363
mod dwarf;
64-
mod windows;
6564

6665
// Entry point for catching an exception, implemented using the `try` intrinsic
6766
// in the compiler.

src/libpanic_unwind/seh.rs

+46-49
Original file line numberDiff line numberDiff line change
@@ -51,9 +51,7 @@ use alloc::boxed::Box;
5151
use core::any::Any;
5252
use core::mem;
5353
use core::raw;
54-
55-
use crate::windows as c;
56-
use libc::{c_int, c_uint};
54+
use libc::{c_int, c_uint, c_void};
5755

5856
// First up, a whole bunch of type definitions. There's a few platform-specific
5957
// oddities here, and a lot that's just blatantly copied from LLVM. The purpose
@@ -76,18 +74,19 @@ use libc::{c_int, c_uint};
7674
// sort of operation. For example, if you compile this C++ code on MSVC and emit
7775
// the LLVM IR:
7876
//
79-
// #include <stdin.h>
77+
// #include <stdint.h>
78+
//
79+
// struct rust_panic {
80+
// uint64_t x[2];
81+
// }
8082
//
8183
// void foo() {
82-
// uint64_t a[2] = {0, 1};
84+
// rust_panic a = {0, 1};
8385
// throw a;
8486
// }
8587
//
8688
// That's essentially what we're trying to emulate. Most of the constant values
87-
// below were just copied from LLVM, I'm at least not 100% sure what's going on
88-
// everywhere. For example the `.PA_K\0` and `.PEA_K\0` strings below (stuck in
89-
// the names of a few of these) I'm not actually sure what they do, but it seems
90-
// to mirror what LLVM does!
89+
// below were just copied from LLVM,
9190
//
9291
// In any case, these structures are all constructed in a similar manner, and
9392
// it's just somewhat verbose for us.
@@ -98,10 +97,9 @@ use libc::{c_int, c_uint};
9897
#[macro_use]
9998
mod imp {
10099
pub type ptr_t = *mut u8;
101-
pub const OFFSET: i32 = 4;
102100

101+
#[cfg(bootstrap)]
103102
pub const NAME1: [u8; 7] = [b'.', b'P', b'A', b'_', b'K', 0, 0];
104-
pub const NAME2: [u8; 7] = [b'.', b'P', b'A', b'X', 0, 0, 0];
105103

106104
macro_rules! ptr {
107105
(0) => (core::ptr::null_mut());
@@ -113,10 +111,9 @@ mod imp {
113111
#[macro_use]
114112
mod imp {
115113
pub type ptr_t = u32;
116-
pub const OFFSET: i32 = 8;
117114

115+
#[cfg(bootstrap)]
118116
pub const NAME1: [u8; 7] = [b'.', b'P', b'E', b'A', b'_', b'K', 0];
119-
pub const NAME2: [u8; 7] = [b'.', b'P', b'E', b'A', b'X', 0, 0];
120117

121118
extern "C" {
122119
pub static __ImageBase: u8;
@@ -141,7 +138,7 @@ pub struct _ThrowInfo {
141138
#[repr(C)]
142139
pub struct _CatchableTypeArray {
143140
pub nCatchableTypes: c_int,
144-
pub arrayOfCatchableTypes: [imp::ptr_t; 2],
141+
pub arrayOfCatchableTypes: [imp::ptr_t; 1],
145142
}
146143

147144
#[repr(C)]
@@ -164,9 +161,19 @@ pub struct _PMD {
164161
pub struct _TypeDescriptor {
165162
pub pVFTable: *const u8,
166163
pub spare: *mut u8,
164+
#[cfg(bootstrap)]
167165
pub name: [u8; 7],
166+
#[cfg(not(bootstrap))]
167+
pub name: [u8; 11],
168168
}
169169

170+
// Note that we intentionally ignore name mangling rules here: we don't want C++
171+
// to be able to catch Rust panics by simply declaring a `struct rust_panic`.
172+
#[cfg(bootstrap)]
173+
use imp::NAME1 as TYPE_NAME;
174+
#[cfg(not(bootstrap))]
175+
const TYPE_NAME: [u8; 11] = *b"rust_panic\0";
176+
170177
static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
171178
attributes: 0,
172179
pnfnUnwind: ptr!(0),
@@ -175,31 +182,22 @@ static mut THROW_INFO: _ThrowInfo = _ThrowInfo {
175182
};
176183

177184
static mut CATCHABLE_TYPE_ARRAY: _CatchableTypeArray = _CatchableTypeArray {
178-
nCatchableTypes: 2,
179-
arrayOfCatchableTypes: [ptr!(0), ptr!(0)],
185+
nCatchableTypes: 1,
186+
arrayOfCatchableTypes: [ptr!(0)],
180187
};
181188

182-
static mut CATCHABLE_TYPE1: _CatchableType = _CatchableType {
183-
properties: 1,
189+
static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
190+
properties: 0,
184191
pType: ptr!(0),
185192
thisDisplacement: _PMD {
186193
mdisp: 0,
187194
pdisp: -1,
188195
vdisp: 0,
189196
},
190-
sizeOrOffset: imp::OFFSET,
191-
copy_function: ptr!(0),
192-
};
193-
194-
static mut CATCHABLE_TYPE2: _CatchableType = _CatchableType {
195-
properties: 1,
196-
pType: ptr!(0),
197-
thisDisplacement: _PMD {
198-
mdisp: 0,
199-
pdisp: -1,
200-
vdisp: 0,
201-
},
202-
sizeOrOffset: imp::OFFSET,
197+
#[cfg(bootstrap)]
198+
sizeOrOffset: mem::size_of::<*mut u64>() as c_int,
199+
#[cfg(not(bootstrap))]
200+
sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
203201
copy_function: ptr!(0),
204202
};
205203

@@ -221,16 +219,10 @@ extern "C" {
221219
//
222220
// Again, I'm not entirely sure what this is describing, it just seems to work.
223221
#[cfg_attr(not(test), lang = "msvc_try_filter")]
224-
static mut TYPE_DESCRIPTOR1: _TypeDescriptor = _TypeDescriptor {
222+
static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
225223
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
226224
spare: core::ptr::null_mut(),
227-
name: imp::NAME1,
228-
};
229-
230-
static mut TYPE_DESCRIPTOR2: _TypeDescriptor = _TypeDescriptor {
231-
pVFTable: unsafe { &TYPE_INFO_VTABLE } as *const _ as *const _,
232-
spare: core::ptr::null_mut(),
233-
name: imp::NAME2,
225+
name: TYPE_NAME,
234226
};
235227

236228
pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
@@ -246,6 +238,11 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
246238
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
247239
let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
248240
let mut ptrs_ptr = ptrs.as_mut_ptr();
241+
let throw_ptr = if cfg!(bootstrap) {
242+
&mut ptrs_ptr as *mut _ as *mut _
243+
} else {
244+
ptrs_ptr as *mut _
245+
};
249246

250247
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
251248
// 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 {
270267
atomic_store(&mut THROW_INFO.pCatchableTypeArray as *mut _ as *mut u32,
271268
ptr!(&CATCHABLE_TYPE_ARRAY as *const _) as u32);
272269
atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[0] as *mut _ as *mut u32,
273-
ptr!(&CATCHABLE_TYPE1 as *const _) as u32);
274-
atomic_store(&mut CATCHABLE_TYPE_ARRAY.arrayOfCatchableTypes[1] as *mut _ as *mut u32,
275-
ptr!(&CATCHABLE_TYPE2 as *const _) as u32);
276-
atomic_store(&mut CATCHABLE_TYPE1.pType as *mut _ as *mut u32,
277-
ptr!(&TYPE_DESCRIPTOR1 as *const _) as u32);
278-
atomic_store(&mut CATCHABLE_TYPE2.pType as *mut _ as *mut u32,
279-
ptr!(&TYPE_DESCRIPTOR2 as *const _) as u32);
270+
ptr!(&CATCHABLE_TYPE as *const _) as u32);
271+
atomic_store(&mut CATCHABLE_TYPE.pType as *mut _ as *mut u32,
272+
ptr!(&TYPE_DESCRIPTOR as *const _) as u32);
273+
274+
extern "system" {
275+
#[unwind(allowed)]
276+
pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !;
277+
}
280278

281-
c::_CxxThrowException(&mut ptrs_ptr as *mut _ as *mut _,
282-
&mut THROW_INFO as *mut _ as *mut _);
283-
u32::max_value()
279+
_CxxThrowException(throw_ptr,
280+
&mut THROW_INFO as *mut _ as *mut _);
284281
}
285282

286283
pub fn payload() -> [u64; 2] {

src/libpanic_unwind/windows.rs

-86
This file was deleted.

src/librustc_codegen_llvm/intrinsic.rs

+14-17
Original file line numberDiff line numberDiff line change
@@ -849,7 +849,7 @@ fn codegen_msvc_try(
849849
// We're generating an IR snippet that looks like:
850850
//
851851
// declare i32 @rust_try(%func, %data, %ptr) {
852-
// %slot = alloca i64*
852+
// %slot = alloca [2 x i64]
853853
// invoke %func(%data) to label %normal unwind label %catchswitch
854854
//
855855
// normal:
@@ -873,21 +873,25 @@ fn codegen_msvc_try(
873873
//
874874
// #include <stdint.h>
875875
//
876+
// struct rust_panic {
877+
// uint64_t x[2];
878+
// }
879+
//
876880
// int bar(void (*foo)(void), uint64_t *ret) {
877881
// try {
878882
// foo();
879883
// return 0;
880-
// } catch(uint64_t a[2]) {
881-
// ret[0] = a[0];
882-
// ret[1] = a[1];
884+
// } catch(rust_panic a) {
885+
// ret[0] = a.x[0];
886+
// ret[1] = a.x[1];
883887
// return 1;
884888
// }
885889
// }
886890
//
887891
// More information can be found in libstd's seh.rs implementation.
888-
let i64p = bx.type_ptr_to(bx.type_i64());
889-
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
890-
let slot = bx.alloca(i64p, ptr_align);
892+
let i64_2 = bx.type_array(bx.type_i64(), 2);
893+
let i64_align = bx.tcx().data_layout.i64_align.abi;
894+
let slot = bx.alloca(i64_2, i64_align);
891895
bx.invoke(func, &[data], normal.llbb(), catchswitch.llbb(), None);
892896

893897
normal.ret(bx.const_i32(0));
@@ -900,17 +904,10 @@ fn codegen_msvc_try(
900904
None => bug!("msvc_try_filter not defined"),
901905
};
902906
let funclet = catchpad.catch_pad(cs, &[tydesc, bx.const_i32(0), slot]);
903-
let addr = catchpad.load(slot, ptr_align);
904907

905-
let i64_align = bx.tcx().data_layout.i64_align.abi;
906-
let arg1 = catchpad.load(addr, i64_align);
907-
let val1 = bx.const_i32(1);
908-
let gep1 = catchpad.inbounds_gep(addr, &[val1]);
909-
let arg2 = catchpad.load(gep1, i64_align);
910-
let local_ptr = catchpad.bitcast(local_ptr, i64p);
911-
let gep2 = catchpad.inbounds_gep(local_ptr, &[val1]);
912-
catchpad.store(arg1, local_ptr, i64_align);
913-
catchpad.store(arg2, gep2, i64_align);
908+
let payload = catchpad.load(slot, i64_align);
909+
let local_ptr = catchpad.bitcast(local_ptr, bx.type_ptr_to(i64_2));
910+
catchpad.store(payload, local_ptr, i64_align);
914911
catchpad.catch_ret(&funclet, caught.llbb());
915912

916913
caught.ret(bx.const_i32(1));

src/test/run-make-fulldeps/foreign-exceptions/foo.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ void println(const char* s) {
88
}
99

1010
struct exception {};
11+
struct rust_panic {};
1112

1213
struct drop_check {
1314
bool* ok;
@@ -45,7 +46,7 @@ extern "C" {
4546
x.ok = NULL;
4647
try {
4748
cb();
48-
} catch (exception e) {
49+
} catch (rust_panic e) {
4950
assert(false && "shouldn't be able to catch a rust panic");
5051
} catch (...) {
5152
println("caught foreign exception in catch (...)");

0 commit comments

Comments
 (0)