Skip to content

Commit ae874bc

Browse files
authored
Rollup merge of #143651 - Fulgen301:seh-exception-ptr, r=ChrisDenton
Win: Use exceptions with empty data for SEH panic exception copies instead of a new panic For unwinding with SEH, we currently construct a C++ exception with the panic data. Being a regular C++ exception, it interacts with the C++ exception handling machinery and can be retrieved via `std::current_exception`, which needs to copy the exception. We can't support that, so we panic, which throws another exception, which the C++ runtime tries to copy and store into the exception_ptr, which panics again, which causes the C++ runtime to store a `bad_exception` instance. However, this doesn't work because the panics thrown by the copy function will be dropped without being rethrown, and causes unnecessary log spam in stderr. Fix this by directly throwing an exception without data, which doesn't cause log spam and can be dropped without being rethrown. Fixes #143623. This also happens to be the solution `@dpaoliello` suggested, though I'm not sure how to handle the commit credit attribution.
2 parents 8989c62 + 96cdbb9 commit ae874bc

File tree

1 file changed

+14
-4
lines changed
  • library/panic_unwind/src

1 file changed

+14
-4
lines changed

library/panic_unwind/src/seh.rs

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ struct Exception {
6161
// and its destructor is executed by the C++ runtime. When we take the Box
6262
// out of the exception, we need to leave the exception in a valid state
6363
// for its destructor to run without double-dropping the Box.
64+
// We also construct this as None for copies of the exception.
6465
data: Option<Box<dyn Any + Send>>,
6566
}
6667

@@ -264,7 +265,11 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
264265
// runtime under a try/catch block and the panic that we generate here will be
265266
// used as the result of the exception copy. This is used by the C++ runtime to
266267
// support capturing exceptions with std::exception_ptr, which we can't support
267-
// because Box<dyn Any> isn't clonable.
268+
// because Box<dyn Any> isn't clonable. Thus we throw an exception without data,
269+
// which the C++ runtime will attempt to copy, which will once again fail, and
270+
// a std::bad_exception instance ends up in the std::exception_ptr instance.
271+
// The lack of data doesn't matter because the exception will never be rethrown
272+
// - it is purely used to signal to the C++ runtime that copying failed.
268273
macro_rules! define_cleanup {
269274
($abi:tt $abi2:tt) => {
270275
unsafe extern $abi fn exception_cleanup(e: *mut Exception) {
@@ -278,7 +283,9 @@ macro_rules! define_cleanup {
278283
unsafe extern $abi2 fn exception_copy(
279284
_dest: *mut Exception, _src: *mut Exception
280285
) -> *mut Exception {
281-
panic!("Rust panics cannot be copied");
286+
unsafe {
287+
throw_exception(None);
288+
}
282289
}
283290
}
284291
}
@@ -291,6 +298,10 @@ cfg_if::cfg_if! {
291298
}
292299

293300
pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
301+
unsafe { throw_exception(Some(data)) }
302+
}
303+
304+
unsafe fn throw_exception(data: Option<Box<dyn Any + Send>>) -> ! {
294305
use core::intrinsics::{AtomicOrdering, atomic_store};
295306

296307
// _CxxThrowException executes entirely on this stack frame, so there's no
@@ -300,8 +311,7 @@ pub(crate) unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
300311
// The ManuallyDrop is needed here since we don't want Exception to be
301312
// dropped when unwinding. Instead it will be dropped by exception_cleanup
302313
// which is invoked by the C++ runtime.
303-
let mut exception =
304-
ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data: Some(data) });
314+
let mut exception = ManuallyDrop::new(Exception { canary: (&raw const TYPE_DESCRIPTOR), data });
305315
let throw_ptr = (&raw mut exception) as *mut _;
306316

307317
// This... may seems surprising, and justifiably so. On 32-bit MSVC the

0 commit comments

Comments
 (0)