about summary refs log tree commit diff
path: root/library/alloc/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/alloc/src')
-rw-r--r--library/alloc/src/boxed.rs1
-rw-r--r--library/alloc/src/sync.rs20
-rw-r--r--library/alloc/src/tests.rs24
3 files changed, 26 insertions, 19 deletions
diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs
index 44a37899007..241b11c3f5f 100644
--- a/library/alloc/src/boxed.rs
+++ b/library/alloc/src/boxed.rs
@@ -214,6 +214,7 @@ impl<T> Box<T> {
     #[inline(always)]
     #[stable(feature = "rust1", since = "1.0.0")]
     #[must_use]
+    #[rustc_diagnostic_item = "box_new"]
     pub fn new(x: T) -> Self {
         #[rustc_box]
         Box::new(x)
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs
index fdd341a06ef..f37573c6f27 100644
--- a/library/alloc/src/sync.rs
+++ b/library/alloc/src/sync.rs
@@ -51,8 +51,16 @@ mod tests;
 ///
 /// Going above this limit will abort your program (although not
 /// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
+/// Trying to go above it might call a `panic` (if not actually going above it).
+///
+/// This is a global invariant, and also applies when using a compare-exchange loop.
+///
+/// See comment in `Arc::clone`.
 const MAX_REFCOUNT: usize = (isize::MAX) as usize;
 
+/// The error in case either counter reaches above `MAX_REFCOUNT`, and we can `panic` safely.
+const INTERNAL_OVERFLOW_ERROR: &str = "Arc counter overflow";
+
 #[cfg(not(sanitize = "thread"))]
 macro_rules! acquire {
     ($x:expr) => {
@@ -1104,6 +1112,9 @@ impl<T: ?Sized> Arc<T> {
                 continue;
             }
 
+            // We can't allow the refcount to increase much past `MAX_REFCOUNT`.
+            assert!(cur <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR);
+
             // NOTE: this code currently ignores the possibility of overflow
             // into usize::MAX; in general both Rc and Arc need to be adjusted
             // to deal with overflow.
@@ -1519,6 +1530,11 @@ impl<T: ?Sized> Clone for Arc<T> {
         // the worst already happened and we actually do overflow the `usize` counter. However, that
         // requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment
         // above and the `abort` below, which seems exceedingly unlikely.
+        //
+        // This is a global invariant, and also applies when using a compare-exchange loop to increment
+        // counters in other methods.
+        // Otherwise, the counter could be brought to an almost-overflow using a compare-exchange loop,
+        // and then overflow using a few `fetch_add`s.
         if old_size > MAX_REFCOUNT {
             abort();
         }
@@ -2180,9 +2196,7 @@ impl<T: ?Sized> Weak<T> {
                     return None;
                 }
                 // See comments in `Arc::clone` for why we do this (for `mem::forget`).
-                if n > MAX_REFCOUNT {
-                    abort();
-                }
+                assert!(n <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR);
                 Some(n + 1)
             })
             .ok()
diff --git a/library/alloc/src/tests.rs b/library/alloc/src/tests.rs
index 299ed156a5d..b1d3a9fa8ac 100644
--- a/library/alloc/src/tests.rs
+++ b/library/alloc/src/tests.rs
@@ -4,7 +4,6 @@ use core::any::Any;
 use core::clone::Clone;
 use core::convert::TryInto;
 use core::ops::Deref;
-use core::result::Result::{Err, Ok};
 
 use std::boxed::Box;
 
@@ -15,7 +14,7 @@ fn test_owned_clone() {
     assert!(a == b);
 }
 
-#[derive(PartialEq, Eq)]
+#[derive(Debug, PartialEq, Eq)]
 struct Test;
 
 #[test]
@@ -23,24 +22,17 @@ fn any_move() {
     let a = Box::new(8) as Box<dyn Any>;
     let b = Box::new(Test) as Box<dyn Any>;
 
-    match a.downcast::<i32>() {
-        Ok(a) => {
-            assert!(a == Box::new(8));
-        }
-        Err(..) => panic!(),
-    }
-    match b.downcast::<Test>() {
-        Ok(a) => {
-            assert!(a == Box::new(Test));
-        }
-        Err(..) => panic!(),
-    }
+    let a: Box<i32> = a.downcast::<i32>().unwrap();
+    assert_eq!(*a, 8);
+
+    let b: Box<Test> = b.downcast::<Test>().unwrap();
+    assert_eq!(*b, Test);
 
     let a = Box::new(8) as Box<dyn Any>;
     let b = Box::new(Test) as Box<dyn Any>;
 
-    assert!(a.downcast::<Box<Test>>().is_err());
-    assert!(b.downcast::<Box<i32>>().is_err());
+    assert!(a.downcast::<Box<i32>>().is_err());
+    assert!(b.downcast::<Box<Test>>().is_err());
 }
 
 #[test]