diff --git a/src/arc.rs b/src/arc.rs index fa3774f..d697143 100644 --- a/src/arc.rs +++ b/src/arc.rs @@ -252,13 +252,26 @@ impl HeaderSlice { } } +impl HeaderSlice { + /// Get a fat reference to the full HeaderSlice from raw pointer. + /// + /// # Safety + /// `ptr` must point to a valid `HeaderSlice` that was allocated + /// with space for `length` elements of `T` after the header. + pub(crate) unsafe fn as_fat_ref<'a>(ptr: *const Self) -> &'a HeaderSlice { + let len = unsafe { (*ptr).length }; + let fake_slice: *const [T] = ptr::slice_from_raw_parts(ptr as *const T, len); + unsafe { &*(fake_slice as *const HeaderSlice) } + } +} + impl Deref for HeaderSlice { type Target = HeaderSlice; fn deref(&self) -> &Self::Target { - let len = self.length; - let fake_slice: *const [T] = ptr::slice_from_raw_parts(self as *const _ as *const T, len); - unsafe { &*(fake_slice as *const HeaderSlice) } + // Use raw pointer to avoid creating a reference with provenance + // limited to the thin [T; 0] type when the allocation is larger. + unsafe { Self::as_fat_ref(self as *const Self) } } } @@ -279,7 +292,7 @@ impl Deref for HeaderSlice { /// via `HeaderSlice`. #[repr(transparent)] pub(crate) struct ThinArc { - ptr: ptr::NonNull>>, + pub(crate) ptr: ptr::NonNull>>, phantom: PhantomData<(H, T)>, } diff --git a/src/green/node.rs b/src/green/node.rs index d056abb..a26cef0 100644 --- a/src/green/node.rs +++ b/src/green/node.rs @@ -186,10 +186,15 @@ impl ops::Deref for GreenNode { #[inline] fn deref(&self) -> &GreenNodeData { - let repr: &Repr = &self.ptr; + // SAFETY: GreenNodeData is #[repr(transparent)] over ReprThin, + // and ThinArc's inner pointer points to ArcInner. + // We access the data field via raw pointer to avoid creating + // an intermediate fat reference that would need to be shrunk + // (which Miri flags as UB under stacked/tree borrows). unsafe { - let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); - mem::transmute::<&ReprThin, &GreenNodeData>(repr) + let inner = self.ptr.ptr.as_ptr(); + let data = ptr::addr_of!((*inner).data); + &*(data as *const ReprThin as *const GreenNodeData) } } } diff --git a/src/green/token.rs b/src/green/token.rs index 9e6a1f0..fb5e719 100644 --- a/src/green/token.rs +++ b/src/green/token.rs @@ -145,10 +145,12 @@ impl ops::Deref for GreenToken { #[inline] fn deref(&self) -> &GreenTokenData { + // SAFETY: Same pattern as GreenNode::deref — access the thin + // data pointer directly to avoid fat→thin reference shrinking. unsafe { - let repr: &Repr = &self.ptr; - let repr: &ReprThin = &*(repr as *const Repr as *const ReprThin); - mem::transmute::<&ReprThin, &GreenTokenData>(repr) + let inner = self.ptr.ptr.as_ptr(); + let data = ptr::addr_of!((*inner).data); + &*(data as *const ReprThin as *const GreenTokenData) } } }