Skip to content

Commit 823174f

Browse files
authored
Rollup merge of rust-lang#108708 - noamtashma:issue-108706-fix, r=m-ou-se
Prevent overflow through Arc::downgrade Fixes rust-lang#108706
2 parents 21f06db + 620544e commit 823174f

File tree

1 file changed

+17
-3
lines changed

1 file changed

+17
-3
lines changed

Diff for: library/alloc/src/sync.rs

+17-3
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,16 @@ mod tests;
5151
///
5252
/// Going above this limit will abort your program (although not
5353
/// necessarily) at _exactly_ `MAX_REFCOUNT + 1` references.
54+
/// Trying to go above it might call a `panic` (if not actually going above it).
55+
///
56+
/// This is a global invariant, and also applies when using a compare-exchange loop.
57+
///
58+
/// See comment in `Arc::clone`.
5459
const MAX_REFCOUNT: usize = (isize::MAX) as usize;
5560

61+
/// The error in case either counter reaches above `MAX_REFCOUNT`, and we can `panic` safely.
62+
const INTERNAL_OVERFLOW_ERROR: &str = "Arc counter overflow";
63+
5664
#[cfg(not(sanitize = "thread"))]
5765
macro_rules! acquire {
5866
($x:expr) => {
@@ -1104,6 +1112,9 @@ impl<T: ?Sized> Arc<T> {
11041112
continue;
11051113
}
11061114

1115+
// We can't allow the refcount to increase much past `MAX_REFCOUNT`.
1116+
assert!(cur <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR);
1117+
11071118
// NOTE: this code currently ignores the possibility of overflow
11081119
// into usize::MAX; in general both Rc and Arc need to be adjusted
11091120
// to deal with overflow.
@@ -1519,6 +1530,11 @@ impl<T: ?Sized> Clone for Arc<T> {
15191530
// the worst already happened and we actually do overflow the `usize` counter. However, that
15201531
// requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment
15211532
// above and the `abort` below, which seems exceedingly unlikely.
1533+
//
1534+
// This is a global invariant, and also applies when using a compare-exchange loop to increment
1535+
// counters in other methods.
1536+
// Otherwise, the counter could be brought to an almost-overflow using a compare-exchange loop,
1537+
// and then overflow using a few `fetch_add`s.
15221538
if old_size > MAX_REFCOUNT {
15231539
abort();
15241540
}
@@ -2180,9 +2196,7 @@ impl<T: ?Sized> Weak<T> {
21802196
return None;
21812197
}
21822198
// See comments in `Arc::clone` for why we do this (for `mem::forget`).
2183-
if n > MAX_REFCOUNT {
2184-
abort();
2185-
}
2199+
assert!(n <= MAX_REFCOUNT, "{}", INTERNAL_OVERFLOW_ERROR);
21862200
Some(n + 1)
21872201
})
21882202
.ok()

0 commit comments

Comments
 (0)