Skip to content

Commit 9a659c5

Browse files
authored
Rollup merge of #73845 - CAD97:weak-as-unsized-ptr, r=RalfJung
Use &raw in A|Rc::as_ptr This PR uses `&raw` for offsetting `*mut [A]RcInner<T> -> *mut T`. Additionally, this updates the implementation of `Weak::as_ptr` to support unsized `T`, though it does not yet relax the bounds of `Weak::as_ptr`/`into_raw`/`from_raw` to accept unsized `T`.
2 parents 50dcefc + 1b5ac57 commit 9a659c5

File tree

3 files changed

+59
-44
lines changed

3 files changed

+59
-44
lines changed

src/liballoc/lib.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@
100100
#![feature(fundamental)]
101101
#![feature(internal_uninit_const)]
102102
#![feature(lang_items)]
103+
#![feature(layout_for_ptr)]
103104
#![feature(libc)]
104105
#![feature(negative_impls)]
105106
#![feature(new_uninit)]
@@ -109,6 +110,7 @@
109110
#![feature(pattern)]
110111
#![feature(ptr_internals)]
111112
#![feature(ptr_offset_from)]
113+
#![feature(raw_ref_op)]
112114
#![feature(rustc_attrs)]
113115
#![feature(receiver_trait)]
114116
#![feature(min_specialization)]

src/liballoc/rc.rs

Lines changed: 29 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -245,7 +245,7 @@ use core::hash::{Hash, Hasher};
245245
use core::intrinsics::abort;
246246
use core::iter;
247247
use core::marker::{self, PhantomData, Unpin, Unsize};
248-
use core::mem::{self, align_of, align_of_val, forget, size_of_val};
248+
use core::mem::{self, align_of_val_raw, forget, size_of_val};
249249
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
250250
use core::pin::Pin;
251251
use core::ptr::{self, NonNull};
@@ -591,17 +591,11 @@ impl<T: ?Sized> Rc<T> {
591591
#[stable(feature = "weak_into_raw", since = "1.45.0")]
592592
pub fn as_ptr(this: &Self) -> *const T {
593593
let ptr: *mut RcBox<T> = NonNull::as_ptr(this.ptr);
594-
let fake_ptr = ptr as *mut T;
595594

596-
// SAFETY: This cannot go through Deref::deref.
597-
// Instead, we manually offset the pointer rather than manifesting a reference.
598-
// This is so that the returned pointer retains the same provenance as our pointer.
599-
// This is required so that e.g. `get_mut` can write through the pointer
600-
// after the Rc is recovered through `from_raw`.
601-
unsafe {
602-
let offset = data_offset(&(*ptr).value);
603-
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
604-
}
595+
// SAFETY: This cannot go through Deref::deref or Rc::inner because
596+
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
597+
// write through the pointer after the Rc is recovered through `from_raw`.
598+
unsafe { &raw const (*ptr).value }
605599
}
606600

607601
/// Constructs an `Rc<T>` from a raw pointer.
@@ -1647,6 +1641,7 @@ pub struct Weak<T: ?Sized> {
16471641
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
16481642
// to allocate space on the heap. That's not a value a real pointer
16491643
// will ever have because RcBox has alignment at least 2.
1644+
// This is only possible when `T: Sized`; unsized `T` never dangle.
16501645
ptr: NonNull<RcBox<T>>,
16511646
}
16521647

@@ -1708,9 +1703,18 @@ impl<T> Weak<T> {
17081703
/// [`null`]: ../../std/ptr/fn.null.html
17091704
#[stable(feature = "weak_into_raw", since = "1.45.0")]
17101705
pub fn as_ptr(&self) -> *const T {
1711-
let offset = data_offset_sized::<T>();
1712-
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
1713-
ptr as *const T
1706+
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
1707+
1708+
// SAFETY: we must offset the pointer manually, and said pointer may be
1709+
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
1710+
// because we know that a pointer to unsized T was derived from a real
1711+
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
1712+
// is used so that we can use the same code path for the non-dangling
1713+
// unsized case and the potentially dangling sized case.
1714+
unsafe {
1715+
let offset = data_offset(ptr as *mut T);
1716+
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
1717+
}
17141718
}
17151719

17161720
/// Consumes the `Weak<T>` and turns it into a raw pointer.
@@ -2113,19 +2117,22 @@ impl<T: ?Sized> AsRef<T> for Rc<T> {
21132117
#[stable(feature = "pin", since = "1.33.0")]
21142118
impl<T: ?Sized> Unpin for Rc<T> {}
21152119

2120+
/// Get the offset within an `ArcInner` for
2121+
/// a payload of type described by a pointer.
2122+
///
2123+
/// # Safety
2124+
///
2125+
/// This has the same safety requirements as `align_of_val_raw`. In effect:
2126+
///
2127+
/// - This function is safe for any argument if `T` is sized, and
2128+
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
2129+
/// aquired from the real instance that you are getting this offset for.
21162130
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
21172131
// Align the unsized value to the end of the `RcBox`.
21182132
// Because it is ?Sized, it will always be the last field in memory.
21192133
// Note: This is a detail of the current implementation of the compiler,
21202134
// and is not a guaranteed language detail. Do not rely on it outside of std.
2121-
unsafe { data_offset_align(align_of_val(&*ptr)) }
2122-
}
2123-
2124-
/// Computes the offset of the data field within `RcBox`.
2125-
///
2126-
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
2127-
fn data_offset_sized<T>() -> isize {
2128-
data_offset_align(align_of::<T>())
2135+
unsafe { data_offset_align(align_of_val_raw(ptr)) }
21292136
}
21302137

21312138
#[inline]

src/liballoc/sync.rs

Lines changed: 28 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ use core::hash::{Hash, Hasher};
1616
use core::intrinsics::abort;
1717
use core::iter;
1818
use core::marker::{PhantomData, Unpin, Unsize};
19-
use core::mem::{self, align_of, align_of_val, size_of_val};
19+
use core::mem::{self, align_of_val, size_of_val};
2020
use core::ops::{CoerceUnsized, Deref, DispatchFromDyn, Receiver};
2121
use core::pin::Pin;
2222
use core::ptr::{self, NonNull};
@@ -267,6 +267,7 @@ pub struct Weak<T: ?Sized> {
267267
// `Weak::new` sets this to `usize::MAX` so that it doesn’t need
268268
// to allocate space on the heap. That's not a value a real pointer
269269
// will ever have because RcBox has alignment at least 2.
270+
// This is only possible when `T: Sized`; unsized `T` never dangle.
270271
ptr: NonNull<ArcInner<T>>,
271272
}
272273

@@ -590,17 +591,11 @@ impl<T: ?Sized> Arc<T> {
590591
#[stable(feature = "weak_into_raw", since = "1.45.0")]
591592
pub fn as_ptr(this: &Self) -> *const T {
592593
let ptr: *mut ArcInner<T> = NonNull::as_ptr(this.ptr);
593-
let fake_ptr = ptr as *mut T;
594594

595-
// SAFETY: This cannot go through Deref::deref.
596-
// Instead, we manually offset the pointer rather than manifesting a reference.
597-
// This is so that the returned pointer retains the same provenance as our pointer.
598-
// This is required so that e.g. `get_mut` can write through the pointer
599-
// after the Arc is recovered through `from_raw`.
600-
unsafe {
601-
let offset = data_offset(&(*ptr).data);
602-
set_data_ptr(fake_ptr, (ptr as *mut u8).offset(offset))
603-
}
595+
// SAFETY: This cannot go through Deref::deref or RcBoxPtr::inner because
596+
// this is required to retain raw/mut provenance such that e.g. `get_mut` can
597+
// write through the pointer after the Rc is recovered through `from_raw`.
598+
unsafe { &raw const (*ptr).data }
604599
}
605600

606601
/// Constructs an `Arc<T>` from a raw pointer.
@@ -1476,9 +1471,18 @@ impl<T> Weak<T> {
14761471
/// [`null`]: ../../std/ptr/fn.null.html
14771472
#[stable(feature = "weak_into_raw", since = "1.45.0")]
14781473
pub fn as_ptr(&self) -> *const T {
1479-
let offset = data_offset_sized::<T>();
1480-
let ptr = self.ptr.cast::<u8>().as_ptr().wrapping_offset(offset);
1481-
ptr as *const T
1474+
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
1475+
1476+
// SAFETY: we must offset the pointer manually, and said pointer may be
1477+
// a dangling weak (usize::MAX) if T is sized. data_offset is safe to call,
1478+
// because we know that a pointer to unsized T was derived from a real
1479+
// unsized T, as dangling weaks are only created for sized T. wrapping_offset
1480+
// is used so that we can use the same code path for the non-dangling
1481+
// unsized case and the potentially dangling sized case.
1482+
unsafe {
1483+
let offset = data_offset(ptr as *mut T);
1484+
set_data_ptr(ptr as *mut T, (ptr as *mut u8).wrapping_offset(offset))
1485+
}
14821486
}
14831487

14841488
/// Consumes the `Weak<T>` and turns it into a raw pointer.
@@ -2270,7 +2274,16 @@ impl<T: ?Sized> AsRef<T> for Arc<T> {
22702274
#[stable(feature = "pin", since = "1.33.0")]
22712275
impl<T: ?Sized> Unpin for Arc<T> {}
22722276

2273-
/// Computes the offset of the data field within `ArcInner`.
2277+
/// Get the offset within an `ArcInner` for
2278+
/// a payload of type described by a pointer.
2279+
///
2280+
/// # Safety
2281+
///
2282+
/// This has the same safety requirements as `align_of_val_raw`. In effect:
2283+
///
2284+
/// - This function is safe for any argument if `T` is sized, and
2285+
/// - if `T` is unsized, the pointer must have appropriate pointer metadata
2286+
/// aquired from the real instance that you are getting this offset for.
22742287
unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
22752288
// Align the unsized value to the end of the `ArcInner`.
22762289
// Because it is `?Sized`, it will always be the last field in memory.
@@ -2279,13 +2292,6 @@ unsafe fn data_offset<T: ?Sized>(ptr: *const T) -> isize {
22792292
unsafe { data_offset_align(align_of_val(&*ptr)) }
22802293
}
22812294

2282-
/// Computes the offset of the data field within `ArcInner`.
2283-
///
2284-
/// Unlike [`data_offset`], this doesn't need the pointer, but it works only on `T: Sized`.
2285-
fn data_offset_sized<T>() -> isize {
2286-
data_offset_align(align_of::<T>())
2287-
}
2288-
22892295
#[inline]
22902296
fn data_offset_align(align: usize) -> isize {
22912297
let layout = Layout::new::<ArcInner<()>>();

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy