Skip to content

Commit

Permalink
Rollup merge of rust-lang#108708 - noamtashma:issue-108706-fix, r=m-o…
Browse files Browse the repository at this point in the history
…u-se

Prevent overflow through Arc::downgrade

Fixes rust-lang#108706
  • Loading branch information
matthiaskrgr authored Mar 11, 2023
2 parents 1909d93 + 620544e commit 5adaa71
Showing 1 changed file with 17 additions and 3 deletions.
20 changes: 17 additions & 3 deletions library/alloc/src/sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) => {
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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()
Expand Down

0 comments on commit 5adaa71

Please sign in to comment.