Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 17 additions & 4 deletions src/arc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,13 +252,26 @@ impl<H, T> HeaderSlice<H, [T]> {
}
}

impl<H, T> HeaderSlice<H, [T; 0]> {
/// Get a fat reference to the full HeaderSlice from raw pointer.
///
/// # Safety
/// `ptr` must point to a valid `HeaderSlice<H, [T; 0]>` 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<H, [T]> {
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<H, [T]>) }
}
}

impl<H, T> Deref for HeaderSlice<H, [T; 0]> {
type Target = HeaderSlice<H, [T]>;

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<H, [T]>) }
// 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) }
}
}

Expand All @@ -279,7 +292,7 @@ impl<H, T> Deref for HeaderSlice<H, [T; 0]> {
/// via `HeaderSlice`.
#[repr(transparent)]
pub(crate) struct ThinArc<H, T> {
ptr: ptr::NonNull<ArcInner<HeaderSlice<H, [T; 0]>>>,
pub(crate) ptr: ptr::NonNull<ArcInner<HeaderSlice<H, [T; 0]>>>,
phantom: PhantomData<(H, T)>,
}

Expand Down
11 changes: 8 additions & 3 deletions src/green/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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<ReprThin>.
// 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)
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/green/token.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
Loading