about summary refs log tree commit diff
path: root/src/liballoc
diff options
context:
space:
mode:
Diffstat (limited to 'src/liballoc')
-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"),
         }
     }
 }