@@ -19,47 +19,59 @@ pub(crate) struct PtrLen {
1919 pub len : usize ,
2020}
2121
22+ /// Representation of C++ `std::exception_ptr` for all targets except msvc.
23+ ///
24+ /// This is a single pointer.
25+ #[ repr( C ) ]
26+ #[ derive( Copy , Clone ) ]
27+ #[ cfg( not( target_env = "msvc" ) ) ]
28+ struct CxxExceptionRepr {
29+ ptr : NonNull < u8 > ,
30+ }
31+
32+ /// Representation of C++ `std::exception_ptr` for msvc.
33+ ///
34+ /// Unfortunately, msvc uses EXCEPTION_
35+ #[ repr( C ) ]
36+ #[ derive( Copy , Clone ) ]
37+ #[ cfg( target_env = "msvc" ) ]
38+ struct CxxExceptionRepr {
39+ ptr : NonNull < u8 > ,
40+ }
41+
2242extern "C" {
2343 /// Helper to construct the default exception from the error message.
2444 #[ link_name = "cxxbridge1$default_exception" ]
25- fn default_exception ( ptr : * const u8 , len : usize ) -> * mut u8 ;
45+ fn default_exception ( ptr : * const u8 , len : usize ) -> CxxExceptionRepr ;
2646 /// Helper to clone the instance of `std::exception_ptr` on the C++ side.
2747 #[ link_name = "cxxbridge1$clone_exception" ]
28- fn clone_exception ( ptr : * const u8 ) -> * mut u8 ;
48+ fn clone_exception ( ptr : & CxxExceptionRepr ) -> CxxExceptionRepr ;
2949 /// Helper to drop the instance of `std::exception_ptr` on the C++ side.
3050 #[ link_name = "cxxbridge1$drop_exception" ]
31- fn drop_exception ( ptr : * mut u8 ) ;
51+ fn drop_exception ( ptr : CxxExceptionRepr ) ;
3252}
3353
34- /// C++ exception containing `std::exception_ptr`.
54+ /// C++ exception containing an `std::exception_ptr`.
3555///
3656/// This object is the Rust wrapper over `std::exception_ptr`, so it owns the exception pointer.
3757/// I.e., the exception is either referenced by a `std::exception_ptr` on the C++ side or the
3858/// reference is moved to this object on the Rust side.
3959#[ repr( C ) ]
4060#[ must_use]
41- pub struct CxxException ( NonNull < u8 > ) ;
61+ pub struct CxxException ( CxxExceptionRepr ) ;
4262
4363impl CxxException {
4464 /// Construct the default `rust::Error` exception from the specified `exc_text`.
4565 fn new_default ( exc_text : & str ) -> Self {
46- let exception_ptr = unsafe {
47- default_exception ( exc_text. as_ptr ( ) , exc_text. len ( ) )
48- } ;
49- CxxException (
50- NonNull :: new ( exception_ptr)
51- . expect ( "Exception conversion returned a null pointer" )
52- )
66+ let exception_repr = unsafe { default_exception ( exc_text. as_ptr ( ) , exc_text. len ( ) ) } ;
67+ CxxException ( exception_repr)
5368 }
5469}
5570
5671impl Clone for CxxException {
5772 fn clone ( & self ) -> Self {
58- let clone_ptr = unsafe { clone_exception ( self . 0 . as_ptr ( ) ) } ;
59- Self (
60- NonNull :: new ( clone_ptr)
61- . expect ( "Exception cloning returned a null pointer" )
62- )
73+ let exception_repr = unsafe { clone_exception ( & self . 0 ) } ;
74+ Self ( exception_repr)
6375 }
6476}
6577
@@ -71,7 +83,7 @@ impl From<Exception> for CxxException {
7183
7284impl Drop for CxxException {
7385 fn drop ( & mut self ) {
74- unsafe { drop_exception ( self . 0 . as_ptr ( ) ) } ;
86+ unsafe { drop_exception ( self . 0 ) } ;
7587 }
7688}
7789
@@ -84,49 +96,34 @@ unsafe impl Sync for CxxException {}
8496
8597/// C++ "result" containing `std::exception_ptr` or a `null`.
8698#[ repr( C ) ]
87- pub struct CxxResult ( * mut u8 ) ;
99+ pub struct CxxResult ( Option < CxxException > ) ;
88100
89101impl From < CxxException > for CxxResult {
90102 fn from ( value : CxxException ) -> Self {
91- let res = Self ( value. 0 . as_ptr ( ) ) ;
92- // NOTE: we are copying the pointer, so we need to forget it here,
93- // otherwise we'd double-free the `std::exception_ptr`.
94- core:: mem:: forget ( value) ;
95- res
96- }
97- }
98-
99- impl Drop for CxxResult {
100- fn drop ( & mut self ) {
101- if !self . 0 . is_null ( ) {
102- unsafe { drop_exception ( self . 0 ) } ;
103- }
103+ Self ( Some ( value) )
104104 }
105105}
106106
107107impl CxxResult {
108108 /// Construct an empty `Ok` result.
109109 pub fn new ( ) -> Self {
110- Self ( core :: ptr :: null_mut ( ) )
110+ Self ( None )
111111 }
112112}
113113
114114impl CxxResult {
115115 unsafe fn exception ( self ) -> Result < ( ) , CxxException > {
116116 // SAFETY: We know that the `Result` can only contain a valid `std::exception_ptr` or null.
117- match unsafe { self . 0 . as_mut ( ) } {
117+ match self . 0 {
118118 None => Ok ( ( ) ) ,
119- Some ( ptr) => {
120- let res = CxxException ( NonNull :: from ( ptr) ) ;
121- // NOTE: we are copying the pointer, so we need to forget this
122- // object, otherwise we'd double-free the `std::exception_ptr`.
123- core:: mem:: forget ( self ) ;
124- Err ( res)
125- }
119+ Some ( ptr) => Err ( ptr) ,
126120 }
127121 }
128122}
129123
124+ // Assert that the result is not larger than the exception (`Option` will use the niche).
125+ const _: ( ) = assert ! ( core:: mem:: size_of:: <CxxResult >( ) == core:: mem:: size_of:: <CxxException >( ) ) ;
126+
130127#[ repr( C ) ]
131128pub struct CxxResultWithMessage {
132129 pub ( crate ) res : CxxResult ,
@@ -142,19 +139,20 @@ impl CxxResultWithMessage {
142139 // SAFETY: The message is always given for the exception and we constructed it in
143140 // a `Box` in `cxxbridge1$exception()`. We just reconstruct it here.
144141 let what = unsafe {
145- str:: from_utf8_unchecked_mut (
146- slice:: from_raw_parts_mut ( self . msg . ptr . as_ptr ( ) , self . msg . len ) )
142+ str:: from_utf8_unchecked_mut ( slice:: from_raw_parts_mut (
143+ self . msg . ptr . as_ptr ( ) ,
144+ self . msg . len ,
145+ ) )
147146 } ;
148147 Err ( Exception {
149148 src,
150- what : unsafe { Box :: from_raw ( what) }
149+ what : unsafe { Box :: from_raw ( what) } ,
151150 } )
152151 }
153152 }
154153 }
155154}
156155
157-
158156/// Trait to convert an arbitrary Rust error into a C++ exception.
159157///
160158/// If an implementation of [`ToCxxException`] is explicitly provided for an `E`, then this
@@ -211,9 +209,8 @@ impl<T: Display> ToCxxExceptionDefault for &T {
211209 } ;
212210 // we have sufficient buffer size, just construct from the inplace
213211 // buffer
214- let exc_text = unsafe {
215- std:: str:: from_utf8_unchecked ( & buffer. assume_init_ref ( ) [ 0 ..size] )
216- } ;
212+ let exc_text =
213+ unsafe { std:: str:: from_utf8_unchecked ( & buffer. assume_init_ref ( ) [ 0 ..size] ) } ;
217214 CxxException :: new_default ( exc_text)
218215 }
219216 #[ cfg( not( feature = "std" ) ) ]
@@ -234,8 +231,8 @@ macro_rules! map_rust_error_to_cxx_exception {
234231 // the need for `specialization` feature. Namely, `ToCxxException` for `T` has higher
235232 // weight and is selected before `ToCxxExceptionDefault`, which is defined on `&T` (and
236233 // requires auto-deref). If it's not defined, then the default is used.
237- use $crate:: ToCxxExceptionDefault ;
238234 use $crate:: ToCxxException ;
235+ use $crate:: ToCxxExceptionDefault ;
239236 ( & $err) . to_cxx_exception( )
240237 } ;
241238 exc
@@ -250,7 +247,7 @@ macro_rules! map_rust_result_to_cxx_result {
250247 unsafe { :: core:: ptr:: write( $ret_ptr, ok) } ;
251248 $crate:: private:: CxxResult :: new( )
252249 }
253- Err ( err) => $crate:: private:: CxxResult :: from( err)
250+ Err ( err) => $crate:: private:: CxxResult :: from( err) ,
254251 }
255252 } ;
256253}
0 commit comments