50
50
use alloc:: boxed:: Box ;
51
51
use core:: any:: Any ;
52
52
use core:: mem;
53
- use core:: raw;
54
53
use libc:: { c_int, c_uint, c_void} ;
55
54
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
+
56
63
// First up, a whole bunch of type definitions. There's a few platform-specific
57
64
// oddities here, and a lot that's just blatantly copied from LLVM. The purpose
58
65
// of all this is to implement the `panic` function below through a call to
@@ -186,7 +193,7 @@ static mut CATCHABLE_TYPE: _CatchableType = _CatchableType {
186
193
properties : 0 ,
187
194
pType : ptr ! ( 0 ) ,
188
195
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 ,
190
197
copyFunction : ptr ! ( 0 ) ,
191
198
} ;
192
199
@@ -229,16 +236,16 @@ static mut TYPE_DESCRIPTOR: _TypeDescriptor = _TypeDescriptor {
229
236
// because Box<dyn Any> isn't clonable.
230
237
macro_rules! define_cleanup {
231
238
( $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 ) ;
235
242
super :: __rust_drop_panic( ) ;
236
243
}
237
244
}
238
245
#[ 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 {
242
249
panic!( "Rust panics cannot be copied" ) ;
243
250
}
244
251
}
@@ -257,13 +264,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
257
264
// _CxxThrowException executes entirely on this stack frame, so there's no
258
265
// need to otherwise transfer `data` to the heap. We just pass a stack
259
266
// 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 _ ;
267
269
268
270
// This... may seems surprising, and justifiably so. On 32-bit MSVC the
269
271
// 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 {
312
314
}
313
315
314
316
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 ( )
323
319
}
324
320
325
321
// This is required by the compiler to exist (e.g., it's a lang item), but
0 commit comments