4949
5050use alloc:: boxed:: Box ;
5151use core:: any:: Any ;
52- use core:: mem;
53- use core:: raw;
52+ use core:: mem:: { self , ManuallyDrop } ;
5453use 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.
230237macro_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 }
@@ -258,12 +265,11 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
258265 // need to otherwise transfer `data` to the heap. We just pass a stack
259266 // pointer to this function.
260267 //
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 _ ;
268+ // The ManuallyDrop is needed here since we don't want Exception to be
269+ // dropped when unwinding. Instead it will be dropped by exception_cleanup
270+ // which is invoked by the C++ runtime.
271+ let mut exception = ManuallyDrop :: new ( Exception { data : Some ( data) } ) ;
272+ let throw_ptr = & mut exception as * mut _ as * mut _ ;
267273
268274 // This... may seems surprising, and justifiably so. On 32-bit MSVC the
269275 // pointers between these structure are just that, pointers. On 64-bit MSVC,
@@ -311,8 +317,9 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
311317 _CxxThrowException ( throw_ptr, & mut THROW_INFO as * mut _ as * mut _ ) ;
312318}
313319
314- pub unsafe fn cleanup ( payload : [ u64 ; 2 ] ) -> Box < dyn Any + Send > {
315- mem:: transmute ( raw:: TraitObject { data : payload[ 0 ] as * mut _ , vtable : payload[ 1 ] as * mut _ } )
320+ pub unsafe fn cleanup ( payload : * mut u8 ) -> Box < dyn Any + Send > {
321+ let exception = & mut * ( payload as * mut Exception ) ;
322+ exception. data . take ( ) . unwrap ( )
316323}
317324
318325// This is required by the compiler to exist (e.g., it's a lang item), but
0 commit comments