summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorkennytm <kennytm@gmail.com>2018-07-24 09:49:56 +0800
committerGitHub <noreply@github.com>2018-07-24 09:49:56 +0800
commit3af372ad574bb952f728f18ac7262f1dc6503864 (patch)
treefee47a82a740e7e45db0bed4544640deb4225580
parent4084f0ee8a7112c234e67ff8daf4a0ee1db3abef (diff)
parenta303741334baafa475632f23145695cba80ce8e7 (diff)
downloadrust-3af372ad574bb952f728f18ac7262f1dc6503864.tar.gz
Rollup merge of #52637 - RalfJung:rc, r=joshtriplett
Don't use NonNull::dangling as sentinel value in Rc, Arc Instead, rely on alignment and use usize::MAX as sentinel. Cc #52508 r? @joshtriplett
-rw-r--r--src/liballoc/rc.rs13
-rw-r--r--src/liballoc/sync.rs13
2 files changed, 17 insertions, 9 deletions
diff --git a/src/liballoc/rc.rs b/src/liballoc/rc.rs
index d76acb28df9..be049eb6e5e 100644
--- a/src/liballoc/rc.rs
+++ b/src/liballoc/rc.rs
@@ -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 doesn’t need
- // to allocate space on the heap.
+ // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
+ // to allocate space on the heap. That's not a value a real pointer
+ // will ever have because RcBox has alignment at least 2.
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> {
diff --git a/src/liballoc/sync.rs b/src/liballoc/sync.rs
index 5def0237e7e..a00b6b4e435 100644
--- a/src/liballoc/sync.rs
+++ b/src/liballoc/sync.rs
@@ -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 doesn’t need
- // to allocate space on the heap.
+ // `Weak::new` sets this to `usize::MAX` so that it doesn’t need
+ // to allocate space on the heap. That's not a value a real pointer
+ // will ever have because RcBox has alignment at least 2.
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"),
}
}
}