Weak::into_raw shouldn't translate sentinel value
This commit is contained in:
parent
747dbcb325
commit
b5b6760c03
2 changed files with 21 additions and 27 deletions
|
@ -848,7 +848,7 @@ impl<T: ?Sized> Rc<T> {
|
||||||
pub fn downgrade(this: &Self) -> Weak<T> {
|
pub fn downgrade(this: &Self) -> Weak<T> {
|
||||||
this.inner().inc_weak();
|
this.inner().inc_weak();
|
||||||
// Make sure we do not create a dangling Weak
|
// Make sure we do not create a dangling Weak
|
||||||
debug_assert!(!is_dangling(this.ptr));
|
debug_assert!(!is_dangling(this.ptr.as_ptr()));
|
||||||
Weak { ptr: this.ptr }
|
Weak { ptr: this.ptr }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1837,8 +1837,8 @@ impl<T> Weak<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
|
pub(crate) fn is_dangling<T: ?Sized>(ptr: *mut T) -> bool {
|
||||||
let address = ptr.as_ptr() as *mut () as usize;
|
let address = ptr as *mut () as usize;
|
||||||
address == usize::MAX
|
address == usize::MAX
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1879,17 +1879,15 @@ impl<T: ?Sized> Weak<T> {
|
||||||
pub fn as_ptr(&self) -> *const T {
|
pub fn as_ptr(&self) -> *const T {
|
||||||
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
|
let ptr: *mut RcBox<T> = NonNull::as_ptr(self.ptr);
|
||||||
|
|
||||||
if is_dangling(self.ptr) {
|
if is_dangling(ptr) {
|
||||||
// If the pointer is dangling, we return a null pointer as the dangling sentinel.
|
// If the pointer is dangling, we return the sentinel directly. This cannot be
|
||||||
// We can't return the usize::MAX sentinel, as that could valid if T is ZST.
|
// a valid payload address, as it is at least as aligned as RcBox (usize).
|
||||||
// SAFETY: we have to return a known sentinel here that cannot be produced for
|
ptr as *const T
|
||||||
// a valid pointer, so that `from_raw` can reverse this transformation.
|
|
||||||
(ptr as *mut T).set_ptr_value(ptr::null_mut())
|
|
||||||
} else {
|
} else {
|
||||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||||
// so use raw pointer manipulation.
|
// so use raw pointer manipulation.
|
||||||
unsafe { &raw mut (*ptr).value }
|
unsafe { &raw const (*ptr).value }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1973,10 +1971,9 @@ impl<T: ?Sized> Weak<T> {
|
||||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||||
// See Weak::as_ptr for context on how the input pointer is derived.
|
// See Weak::as_ptr for context on how the input pointer is derived.
|
||||||
|
|
||||||
let ptr = if ptr.is_null() {
|
let ptr = if is_dangling(ptr as *mut T) {
|
||||||
// If we get a null pointer, this is a dangling weak.
|
// This is a dangling Weak.
|
||||||
// SAFETY: this is the same sentinel as used in Weak::new and is_dangling
|
ptr as *mut RcBox<T>
|
||||||
(ptr as *mut RcBox<T>).set_ptr_value(usize::MAX as *mut _)
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
||||||
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
||||||
|
@ -2052,7 +2049,7 @@ impl<T: ?Sized> Weak<T> {
|
||||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||||
if is_dangling(self.ptr) {
|
if is_dangling(self.ptr.as_ptr()) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// We are careful to *not* create a reference covering the "data" field, as
|
// We are careful to *not* create a reference covering the "data" field, as
|
||||||
|
|
|
@ -885,7 +885,7 @@ impl<T: ?Sized> Arc<T> {
|
||||||
match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
|
match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
// Make sure we do not create a dangling Weak
|
// Make sure we do not create a dangling Weak
|
||||||
debug_assert!(!is_dangling(this.ptr));
|
debug_assert!(!is_dangling(this.ptr.as_ptr()));
|
||||||
return Weak { ptr: this.ptr };
|
return Weak { ptr: this.ptr };
|
||||||
}
|
}
|
||||||
Err(old) => cur = old,
|
Err(old) => cur = old,
|
||||||
|
@ -1664,12 +1664,10 @@ impl<T: ?Sized> Weak<T> {
|
||||||
pub fn as_ptr(&self) -> *const T {
|
pub fn as_ptr(&self) -> *const T {
|
||||||
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
|
let ptr: *mut ArcInner<T> = NonNull::as_ptr(self.ptr);
|
||||||
|
|
||||||
if is_dangling(self.ptr) {
|
if is_dangling(ptr) {
|
||||||
// If the pointer is dangling, we return a null pointer as the dangling sentinel.
|
// If the pointer is dangling, we return the sentinel directly. This cannot be
|
||||||
// We can't return the usize::MAX sentinel, as that could valid if T is ZST.
|
// a valid payload address, as it is at least as aligned as ArcInner (usize).
|
||||||
// SAFETY: we have to return a known sentinel here that cannot be produced for
|
ptr as *const T
|
||||||
// a valid pointer, so that `from_raw` can reverse this transformation.
|
|
||||||
(ptr as *mut T).set_ptr_value(ptr::null_mut())
|
|
||||||
} else {
|
} else {
|
||||||
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
// SAFETY: if is_dangling returns false, then the pointer is dereferencable.
|
||||||
// The payload may be dropped at this point, and we have to maintain provenance,
|
// The payload may be dropped at this point, and we have to maintain provenance,
|
||||||
|
@ -1758,10 +1756,9 @@ impl<T: ?Sized> Weak<T> {
|
||||||
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
pub unsafe fn from_raw(ptr: *const T) -> Self {
|
||||||
// See Weak::as_ptr for context on how the input pointer is derived.
|
// See Weak::as_ptr for context on how the input pointer is derived.
|
||||||
|
|
||||||
let ptr = if ptr.is_null() {
|
let ptr = if is_dangling(ptr as *mut T) {
|
||||||
// If we get a null pointer, this is a dangling weak.
|
// This is a dangling Weak.
|
||||||
// SAFETY: this is the same sentinel as used in Weak::new and is_dangling
|
ptr as *mut ArcInner<T>
|
||||||
(ptr as *mut ArcInner<T>).set_ptr_value(usize::MAX as *mut _)
|
|
||||||
} else {
|
} else {
|
||||||
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
// Otherwise, we're guaranteed the pointer came from a nondangling Weak.
|
||||||
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
// SAFETY: data_offset is safe to call, as ptr references a real (potentially dropped) T.
|
||||||
|
@ -1877,7 +1874,7 @@ impl<T: ?Sized> Weak<T> {
|
||||||
/// (i.e., when this `Weak` was created by `Weak::new`).
|
/// (i.e., when this `Weak` was created by `Weak::new`).
|
||||||
#[inline]
|
#[inline]
|
||||||
fn inner(&self) -> Option<WeakInner<'_>> {
|
fn inner(&self) -> Option<WeakInner<'_>> {
|
||||||
if is_dangling(self.ptr) {
|
if is_dangling(self.ptr.as_ptr()) {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
// We are careful to *not* create a reference covering the "data" field, as
|
// We are careful to *not* create a reference covering the "data" field, as
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue