Skip to content

Commit a2a7188

Browse files
committed
Fix and clean up SEH unwinding
1 parent fc97d69 commit a2a7188

File tree

2 files changed

+24
-25
lines changed

2 files changed

+24
-25
lines changed

src/libpanic_unwind/seh.rs

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,16 @@
5050
use alloc::boxed::Box;
5151
use core::any::Any;
5252
use core::mem;
53-
use core::raw;
5453
use libc::{c_int, c_uint, c_void};
5554

55+
struct Exception {
56+
// This needs to be an Option because we catch the exception by reference
57+
// and its destructor is executed by the C++ runtime. When we take the Box
58+
// out of the exception, we need to leave the exception in a valid state
59+
// for its destructor to run without double-dropping the Box.
60+
data: Option<Box<dyn Any + Send>>,
61+
}
62+
5663
// First up, a whole bunch of type definitions. There's a few platform-specific
5764
// oddities here, and a lot that's just blatantly copied from LLVM. The purpose
5865
// of all this is to implement the `panic` function below through a call to
@@ -186,7 +193,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
186193
properties: 0,
187194
pType: ptr!(0),
188195
thisDisplacement: _PMD { mdisp: 0, pdisp: -1, vdisp: 0 },
189-
sizeOrOffset: mem::size_of::<[u64; 2]>() as c_int,
196+
sizeOrOffset: mem::size_of::<Exception>() as c_int,
190197
copyFunction: ptr!(0),
191198
};
192199

@@ -229,16 +236,16 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
229236
// because Box<dyn Any> isn't clonable.
230237
macro_rules! define_cleanup {
231238
($abi:tt) => {
232-
unsafe extern $abi fn exception_cleanup(e: *mut [u64; 2]) {
233-
if (*e)[0] != 0 {
234-
cleanup(*e);
239+
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
240+
if let Some(b) = e.read().data {
241+
drop(b);
235242
super::__rust_drop_panic();
236243
}
237244
}
238245
#[unwind(allowed)]
239-
unsafe extern $abi fn exception_copy(_dest: *mut [u64; 2],
240-
_src: *mut [u64; 2])
241-
-> *mut [u64; 2] {
246+
unsafe extern $abi fn exception_copy(_dest: *mut Exception,
247+
_src: *mut Exception)
248+
-> *mut Exception {
242249
panic!("Rust panics cannot be copied");
243250
}
244251
}
@@ -257,13 +264,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
257264
// _CxxThrowException executes entirely on this stack frame, so there's no
258265
// need to otherwise transfer `data` to the heap. We just pass a stack
259266
// pointer to this function.
260-
//
261-
// The first argument is the payload being thrown (our two pointers), and
262-
// the second argument is the type information object describing the
263-
// exception (constructed above).
264-
let ptrs = mem::transmute::<_, raw::TraitObject>(data);
265-
let mut ptrs = [ptrs.data as u64, ptrs.vtable as u64];
266-
let throw_ptr = ptrs.as_mut_ptr() as *mut _;
267+
let mut exception = Exception { data: Some(data) };
268+
let throw_ptr = &mut exception as *mut _ as *mut _;
267269

268270
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
269271
// pointers between these structure are just that, pointers. On 64-bit MSVC,
@@ -312,14 +314,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
312314
}
313315

314316
pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> {
315-
let payload = *&mut (payload as *mut [u64; 2]);
316-
317-
// Clear the first word of the exception so avoid double-dropping it.
318-
// This will be read by the destructor which is implicitly called at the
319-
// end of the catch block by the runtime.
320-
payload[0] = 0;
321-
322-
mem::transmute(raw::TraitObject { data: payload[0] as *mut _, vtable: payload[1] as *mut _ })
317+
let exception = &mut *(payload as *mut Exception);
318+
exception.data.take().unwrap()
323319
}
324320

325321
// This is required by the compiler to exist (e.g., it's a lang item), but

src/libstd/panicking.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -297,9 +297,12 @@ pub unsafe fn r#try<R, F: FnOnce() -> R>(f: F) -> Result<R, Box<dyn Any + Send>>
297297
let payload_ptr = payload.as_mut_ptr() as *mut u8;
298298
let r = intrinsics::r#try(try_fn, data, payload_ptr);
299299
if r != 0 {
300-
if cfg!(target_env = "msvc") {
300+
#[cfg(target_env = "msvc")]
301+
{
301302
catch_fn(data, payload_ptr)
302-
} else {
303+
}
304+
#[cfg(not(target_env = "msvc"))]
305+
{
303306
catch_fn(data, payload.assume_init())
304307
}
305308
}

0 commit comments

Comments
 (0)