@@ -15,14 +15,48 @@ use alloc::boxed::Box;
15
15
use libc:: { self , c_int} ;
16
16
use unwind as uw;
17
17
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
+
18
51
pub fn payload ( ) -> * mut u8 {
19
52
ptr:: null_mut ( )
20
53
}
21
54
22
55
pub unsafe fn cleanup ( ptr : * mut u8 ) -> Box < dyn Any + Send > {
23
56
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 ( ) ;
26
60
ex
27
61
}
28
62
@@ -32,11 +66,8 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
32
66
if exception == ptr:: null_mut ( ) {
33
67
return uw:: _URC_FATAL_PHASE1_ERROR as u32 ;
34
68
}
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 ( ) ) ;
40
71
}
41
72
42
73
#[ lang = "eh_personality" ]
@@ -52,10 +83,11 @@ unsafe extern "C" fn rust_eh_personality(version: c_int,
52
83
53
84
extern "C" {
54
85
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 ( ) ;
56
88
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 ) -> ! ;
59
91
fn __gxx_personality_v0 ( version : c_int ,
60
92
actions : uw:: _Unwind_Action ,
61
93
exception_class : uw:: _Unwind_Exception_Class ,
0 commit comments