|
49 | 49 | use alloc::boxed::Box; |
50 | 50 | use core::any::Any; |
51 | 51 | use core::mem::{self, ManuallyDrop}; |
| 52 | +use core::ptr; |
52 | 53 | use libc::{c_int, c_uint, c_void}; |
53 | 54 |
|
| 55 | +// NOTE(nbdd0121): The `canary` field will be part of stable ABI after `c_unwind` stabilization. |
| 56 | +#[repr(C)] |
54 | 57 | struct Exception { |
| 58 | + // See `gcc.rs` on why this is present. We already have a static here so just use it. |
| 59 | + canary: *const _TypeDescriptor, |
| 60 | + |
55 | 61 | // This needs to be an Option because we catch the exception by reference |
56 | 62 | // and its destructor is executed by the C++ runtime. When we take the Box |
57 | 63 | // out of the exception, we need to leave the exception in a valid state |
@@ -235,7 +241,7 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor { |
235 | 241 | macro_rules! define_cleanup { |
236 | 242 | ($abi:tt $abi2:tt) => { |
237 | 243 | unsafe extern $abi fn exception_cleanup(e: *mut Exception) { |
238 | | - if let Exception { data: Some(b) } = e.read() { |
| 244 | + if let Exception { data: Some(b), .. } = e.read() { |
239 | 245 | drop(b); |
240 | 246 | super::__rust_drop_panic(); |
241 | 247 | } |
@@ -265,7 +271,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 { |
265 | 271 | // The ManuallyDrop is needed here since we don't want Exception to be |
266 | 272 | // dropped when unwinding. Instead it will be dropped by exception_cleanup |
267 | 273 | // which is invoked by the C++ runtime. |
268 | | - let mut exception = ManuallyDrop::new(Exception { data: Some(data) }); |
| 274 | + let mut exception = ManuallyDrop::new(Exception { canary: &TYPE_DESCRIPTOR, data: Some(data) }); |
269 | 275 | let throw_ptr = &mut exception as *mut _ as *mut _; |
270 | 276 |
|
271 | 277 | // This... may seems surprising, and justifiably so. On 32-bit MSVC the |
@@ -321,8 +327,12 @@ pub unsafe fn cleanup(payload: *mut u8) -> Box<dyn Any + Send> { |
321 | 327 | // __rust_try. This happens when a non-Rust foreign exception is caught. |
322 | 328 | if payload.is_null() { |
323 | 329 | super::__rust_foreign_exception(); |
324 | | - } else { |
325 | | - let exception = &mut *(payload as *mut Exception); |
326 | | - exception.data.take().unwrap() |
327 | 330 | } |
| 331 | + let exception = payload as *mut Exception; |
| 332 | + let canary = ptr::addr_of!((*exception).canary).read(); |
| 333 | + if !ptr::eq(canary, &TYPE_DESCRIPTOR) { |
| 334 | + // A foreign Rust exception. |
| 335 | + super::__rust_foreign_exception(); |
| 336 | + } |
| 337 | + (*exception).data.take().unwrap() |
328 | 338 | } |
0 commit comments