@@ -15,14 +15,48 @@ use alloc::boxed::Box;
1515use libc:: { self , c_int} ;
1616use unwind as uw;
1717
18+ // This matches the layout of std::type_info in C++
19+ #[ repr( C ) ]
20+ struct TypeInfo {
21+ vtable : * const usize ,
22+ name : * const u8 ,
23+ }
24+ unsafe impl Sync for TypeInfo { }
25+
26+ extern "C" {
27+ // The leading `\x01` byte here is actually a magical signal to LLVM to
28+ // *not* apply any other mangling like prefixing with a `_` character.
29+ //
30+ // This symbol is the vtable used by C++'s `std::type_info`. Objects of type
31+ // `std::type_info`, type descriptors, have a pointer to this table. Type
32+ // descriptors are referenced by the C++ EH structures defined above and
33+ // that we construct below.
34+ //
35+ // Note that the real size is larger than 3 usize, but we only need our
36+ // vtable to point to the third element.
37+ #[ link_name = "\x01 _ZTVN10__cxxabiv117__class_type_infoE" ]
38+ static CLASS_TYPE_INFO_VTABLE : [ usize ; 3 ] ;
39+ }
40+
41+ // std::type_info for a rust_panic class
42+ #[ lang = "eh_catch_typeinfo" ]
43+ static EXCEPTION_TYPE_INFO : TypeInfo = TypeInfo {
44+ // Normally we would use .as_ptr().add(2) but this doesn't work in a const context.
45+ vtable : unsafe { & CLASS_TYPE_INFO_VTABLE [ 2 ] } ,
46+ // This intentionally doesn't use the normal name mangling scheme because
47+ // we don't want C++ to be able to produce or catch Rust panics.
48+ name : b"rust_panic\0 " . as_ptr ( ) ,
49+ } ;
50+
1851pub fn payload ( ) -> * mut u8 {
1952 ptr:: null_mut ( )
2053}
2154
2255pub unsafe fn cleanup ( ptr : * mut u8 ) -> Box < dyn Any + Send > {
2356 assert ! ( !ptr. is_null( ) ) ;
24- let ex = ptr:: read ( ptr as * mut _ ) ;
25- __cxa_free_exception ( ptr as * mut _ ) ;
57+ let adjusted_ptr = __cxa_begin_catch ( ptr as * mut libc:: c_void ) ;
58+ let ex = ptr:: read ( adjusted_ptr as * mut _ ) ;
59+ __cxa_end_catch ( ) ;
2660 ex
2761}
2862
@@ -32,11 +66,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
3266 if exception == ptr:: null_mut ( ) {
3367 return uw:: _URC_FATAL_PHASE1_ERROR as u32 ;
3468 }
35- let exception = exception as * mut Box < dyn Any + Send > ;
36- ptr:: write ( exception, data) ;
37- __cxa_throw ( exception as * mut _ , ptr:: null_mut ( ) , ptr:: null_mut ( ) ) ;
38-
39- unreachable ! ( )
69+ ptr:: write ( exception as * mut _ , data) ;
70+ __cxa_throw ( exception as * mut _ , & EXCEPTION_TYPE_INFO , ptr:: null_mut ( ) ) ;
4071}
4172
4273#[ lang = "eh_personality" ]
@@ -52,10 +83,11 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
5283
5384extern "C" {
5485 fn __cxa_allocate_exception ( thrown_size : libc:: size_t ) -> * mut libc:: c_void ;
55- fn __cxa_free_exception ( thrown_exception : * mut libc:: c_void ) ;
86+ fn __cxa_begin_catch ( thrown_exception : * mut libc:: c_void ) -> * mut libc:: c_void ;
87+ fn __cxa_end_catch ( ) ;
5688 fn __cxa_throw ( thrown_exception : * mut libc:: c_void ,
57- tinfo : * mut libc :: c_void ,
58- dest : * mut libc:: c_void ) ;
89+ tinfo : * const TypeInfo ,
90+ dest : * mut libc:: c_void ) -> ! ;
5991 fn __gxx_personality_v0 ( version : c_int ,
6092 actions : uw:: _Unwind_Action ,
6193 exception_class : uw:: _Unwind_Exception_Class ,
0 commit comments