3838
3939use alloc:: boxed:: Box ;
4040use core:: any:: Any ;
41+ use core:: ptr;
4142
4243use unwind as uw;
4344
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.
4454#[ repr( C ) ]
4555struct Exception {
4656 _uwe : uw:: _Unwind_Exception ,
57+ canary : * const u8 ,
4758 cause : Box < dyn Any + Send > ,
4859}
4960
@@ -54,6 +65,7 @@ pub unsafe fn panic(data: Box<dyn Any + Send>) -> u32 {
5465 exception_cleanup,
5566 private : [ 0 ; uw:: unwinder_private_data_size] ,
5667 } ,
68+ canary : & CANARY ,
5769 cause : data,
5870 } ) ;
5971 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> {
7587 if ( * exception) . exception_class != rust_exception_class ( ) {
7688 uw:: _Unwind_DeleteException ( exception) ;
7789 super :: __rust_foreign_exception ( ) ;
78- } else {
79- let exception = Box :: from_raw ( exception as * mut Exception ) ;
80- exception. cause
8190 }
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
82106}
83107
84108// Rust's exception class identifier. This is used by personality routines to
0 commit comments