Don't use NonNull::dangling as sentinel value

Instead, rely on alignment and use usize::MAX as sentinel.
This commit is contained in:
Ralf Jung 2018-07-23 11:13:20 +02:00
parent 210d61f05c
commit 33b8f6253f
2 changed files with 17 additions and 9 deletions

View File

@ -258,6 +258,7 @@ use core::ops::Deref;
use core::ops::CoerceUnsized;
use core::ptr::{self, NonNull};
use core::convert::From;
use core::usize;
use alloc::{Global, Alloc, Layout, box_free, handle_alloc_error};
use string::String;
@ -449,6 +450,8 @@ impl<T: ?Sized> Rc<T> {
#[stable(feature = "rc_weak", since = "1.4.0")]
pub fn downgrade(this: &Self) -> Weak<T> {
this.inc_weak();
// Make sure we do not create a dangling Weak
debug_assert!(!is_dangling(this.ptr));
Weak { ptr: this.ptr }
}
@ -1154,8 +1157,9 @@ impl<T> From<Vec<T>> for Rc<[T]> {
pub struct Weak<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
// `Weak::new` sets this to a dangling pointer so that it doesnt need
// to allocate space on the heap.
// `Weak::new` sets this to `usize::MAX` so that it doesnt need
// to allocate space on the heap. That's not a value a real poiner
// will ever have because RcBox has alignment at least 4.
ptr: NonNull<RcBox<T>>,
}
@ -1185,15 +1189,14 @@ impl<T> Weak<T> {
#[stable(feature = "downgraded_weak", since = "1.10.0")]
pub fn new() -> Weak<T> {
Weak {
ptr: NonNull::dangling(),
ptr: NonNull::new(usize::MAX as *mut RcBox<T>).expect("MAX is not 0"),
}
}
}
pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
let address = ptr.as_ptr() as *mut () as usize;
let align = align_of_val(unsafe { ptr.as_ref() });
address == align
address == usize::MAX
}
impl<T: ?Sized> Weak<T> {

View File

@ -238,8 +238,9 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Arc<U>> for Arc<T> {}
pub struct Weak<T: ?Sized> {
// This is a `NonNull` to allow optimizing the size of this type in enums,
// but it is not necessarily a valid pointer.
// `Weak::new` sets this to a dangling pointer so that it doesnt need
// to allocate space on the heap.
// `Weak::new` sets this to `usize::MAX` so that it doesnt need
// to allocate space on the heap. That's not a value a real poiner
// will ever have because RcBox has alignment at least 4.
ptr: NonNull<ArcInner<T>>,
}
@ -442,7 +443,11 @@ impl<T: ?Sized> Arc<T> {
// synchronize with the write coming from `is_unique`, so that the
// events prior to that write happen before this read.
match this.inner().weak.compare_exchange_weak(cur, cur + 1, Acquire, Relaxed) {
Ok(_) => return Weak { ptr: this.ptr },
Ok(_) => {
// Make sure we do not create a dangling Weak
debug_assert!(!is_dangling(this.ptr));
return Weak { ptr: this.ptr };
}
Err(old) => cur = old,
}
}
@ -1033,7 +1038,7 @@ impl<T> Weak<T> {
#[stable(feature = "downgraded_weak", since = "1.10.0")]
pub fn new() -> Weak<T> {
Weak {
ptr: NonNull::dangling(),
ptr: NonNull::new(usize::MAX as *mut ArcInner<T>).expect("MAX is not 0"),
}
}
}