1- use super :: boxed:: try_box ;
1+ use super :: boxed:: try_new_uninit_box ;
22use super :: context:: ContextError ;
33use super :: ptr:: { MutPtr , OwnedPtr , SharedPtr } ;
44use super :: vtable:: Vtable ;
@@ -18,8 +18,10 @@ use std::backtrace::{Backtrace, BacktraceStatus};
1818///
1919/// # Safety
2020///
21- /// Implementations must correctly report their type (or a type `T` where `*mut
22- /// Self` can be cast to `*mut T` and safely accessed) in `ext_is`.
21+ /// Safety relies on `ext_is` being implemented correctly. Implementations must
22+ /// not lie about whether they are or are not an instance of the given type id's
23+ /// associated type (or a newtype wrapper around that type). Violations will
24+ /// lead to unsafety.
2325pub ( crate ) unsafe trait ErrorExt : core:: error:: Error + Send + Sync + ' static {
2426 /// Get a shared borrow of the next error in the chain.
2527 fn ext_source ( & self ) -> Option < OomOrDynErrorRef < ' _ > > ;
@@ -30,7 +32,8 @@ pub(crate) unsafe trait ErrorExt: core::error::Error + Send + Sync + 'static {
3032 /// Take ownership of the next error in the chain.
3133 fn ext_take_source ( & mut self ) -> Option < OomOrDynError > ;
3234
33- /// Is this error an instance of `T`, where `type_id == TypeId::of::<T>()`?
35+ /// Is this error an instance of `T`, where `type_id == TypeId::of::<T>()`
36+ /// or a newtype wrapper around that type?
3437 ///
3538 /// # Safety
3639 ///
@@ -137,12 +140,16 @@ impl BoxedDynError {
137140 None => crate :: backtrace:: capture ( ) ,
138141 } ;
139142
140- let error = try_box ( ConcreteError {
141- vtable : Vtable :: of :: < E > ( ) ,
142- #[ cfg( feature = "backtrace" ) ]
143- backtrace : Some ( backtrace) ,
144- error,
145- } ) ?;
143+ let boxed = try_new_uninit_box ( ) ?;
144+ let error = Box :: write (
145+ boxed,
146+ ConcreteError {
147+ vtable : Vtable :: of :: < E > ( ) ,
148+ #[ cfg( feature = "backtrace" ) ]
149+ backtrace : Some ( backtrace) ,
150+ error,
151+ } ,
152+ ) ;
146153
147154 // We are going to pun the `ConcreteError<E>` pointer into a `DynError`
148155 // pointer. Debug assert that their layouts are compatible first.
@@ -179,7 +186,8 @@ impl BoxedDynError {
179186 // Safety: `Box::into_raw` always returns a non-null pointer.
180187 let ptr = unsafe { NonNull :: new_unchecked ( ptr) } ;
181188 let ptr = OwnedPtr :: new ( ptr) ;
182- Ok ( Self :: from_owned_ptr ( ptr) )
189+ // Safety: points to a valid `DynError`.
190+ Ok ( unsafe { Self :: from_owned_ptr ( ptr) } )
183191 }
184192
185193 fn into_owned_ptr ( self ) -> OwnedPtr < DynError > {
@@ -188,7 +196,12 @@ impl BoxedDynError {
188196 ptr
189197 }
190198
191- fn from_owned_ptr ( inner : OwnedPtr < DynError > ) -> Self {
199+ /// # Safety
200+ ///
201+ /// The given pointer must be a valid `DynError` pointer: punning a
202+ /// `ConcreteError<?>` and is safe to drop and deallocate with its
203+ /// `DynError::vtable` methods.
204+ unsafe fn from_owned_ptr ( inner : OwnedPtr < DynError > ) -> Self {
192205 BoxedDynError { inner }
193206 }
194207}
@@ -398,6 +411,7 @@ impl BoxedDynError {
398411/// assert_eq!(error.to_string(), "oops I ate worms");
399412/// # }
400413/// ```
414+ #[ repr( transparent) ]
401415pub struct Error {
402416 pub ( crate ) inner : OomOrDynError ,
403417}
@@ -1500,6 +1514,7 @@ impl<'a> OomOrDynErrorMut<'a> {
15001514
15011515/// Bit packed version of `enum { BoxedDynError, OutOfMemory }` that relies on
15021516/// implicit pointer tagging and `OutOfMemory` being zero-sized.
1517+ #[ repr( transparent) ]
15031518pub ( crate ) struct OomOrDynError {
15041519 // Safety: this must always be the casted-to-`u8` version of either (a)
15051520 // `0x1`, or (b) a valid, owned `DynError` pointer. (Note that these cases
@@ -1526,7 +1541,8 @@ impl Drop for OomOrDynError {
15261541 if self . is_boxed_dyn_error ( ) {
15271542 let inner = self . inner . cast :: < DynError > ( ) ;
15281543 let inner = OwnedPtr :: new ( inner) ;
1529- let _ = BoxedDynError :: from_owned_ptr ( inner) ;
1544+ // Safety: the pointer is a valid `DynError` pointer.
1545+ let _ = unsafe { BoxedDynError :: from_owned_ptr ( inner) } ;
15301546 } else {
15311547 debug_assert ! ( self . is_oom( ) ) ;
15321548 }
@@ -1640,11 +1656,9 @@ impl OomOrDynError {
16401656 self ,
16411657 ) -> Box < dyn core:: error:: Error + Send + Sync + ' static > {
16421658 let box_dyn_error_of_oom = || {
1643- let ptr = NonNull :: < OutOfMemory > :: dangling ( ) . as_ptr ( ) ;
1644- // Safety: it is always safe to call `Box::<T>::from_raw` on `T`'s
1645- // dangling pointer if `T` is a unit type.
1646- let boxed = unsafe { Box :: from_raw ( ptr) } ;
1647- boxed as _
1659+ // NB: `Box::new` will never actually allocate for zero-sized types
1660+ // like `OutOfMemory`.
1661+ Box :: new ( OutOfMemory :: new ( ) ) as _
16481662 } ;
16491663
16501664 if self . is_oom ( ) {
0 commit comments