38
38
39
39
use alloc:: boxed:: Box ;
40
40
use core:: any:: Any ;
41
+ use core:: ptr;
41
42
42
43
use unwind as uw;
43
44
45
+ // In case where multiple copies of std is compiled into a single binary,
46
+ // we use address of this static variable to distinguish an exception raised by
47
+ // this copy and some other copy (which needs to be treated as foreign exception).
48
+ static CANARY : u8 = 0 ;
49
+
50
+ // NOTE(nbdd0121)
51
+ // Once `c_unwind` feature is stabilized, there will be ABI stability requirement
52
+ // on this struct. The first two field must be `_Unwind_Exception` and `canary`,
53
+ // as it may be accessed by a different version of the std with a different compiler.
44
54
#[ repr( C ) ]
45
55
struct Exception {
46
56
_uwe : uw:: _Unwind_Exception ,
57
+ canary : * const u8 ,
47
58
cause : Box < dyn Any + Send > ,
48
59
}
49
60
@@ -54,6 +65,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
54
65
exception_cleanup,
55
66
private : [ 0 ; uw:: unwinder_private_data_size] ,
56
67
} ,
68
+ canary : & CANARY ,
57
69
cause : data,
58
70
} ) ;
59
71
let exception_param = Box :: into_raw ( exception) as * mut uw:: _Unwind_Exception ;
@@ -75,10 +87,22 @@ pub unsafe fn cleanup(ptr: *mut u8) -> Box<dyn Any + Send> {
75
87
if ( * exception) . exception_class != rust_exception_class ( ) {
76
88
uw:: _Unwind_DeleteException ( exception) ;
77
89
super :: __rust_foreign_exception ( ) ;
78
- } else {
79
- let exception = Box :: from_raw ( exception as * mut Exception ) ;
80
- exception. cause
81
90
}
91
+
92
+ let exception = exception. cast :: < Exception > ( ) ;
93
+ // Just access the canary field, avoid accessing the entire `Exception` as
94
+ // it can be a foreign Rust exception.
95
+ let canary = ptr:: addr_of!( ( * exception) . canary) . read ( ) ;
96
+ if !ptr:: eq ( canary, & CANARY ) {
97
+ // A foreign Rust exception, treat it slightly differently from other
98
+ // foreign exceptions, because call into `_Unwind_DeleteException` will
99
+ // call into `__rust_drop_panic` which produces a confusing
100
+ // "Rust panic must be rethrown" message.
101
+ super :: __rust_foreign_exception ( ) ;
102
+ }
103
+
104
+ let exception = Box :: from_raw ( exception as * mut Exception ) ;
105
+ exception. cause
82
106
}
83
107
84
108
// Rust's exception class identifier. This is used by personality routines to
0 commit comments