diff options
Diffstat (limited to 'library/alloc/src')
| -rw-r--r-- | library/alloc/src/boxed.rs | 1 | ||||
| -rw-r--r-- | library/alloc/src/sync.rs | 20 | ||||
| -rw-r--r-- | library/alloc/src/tests.rs | 24 |
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] |
