@@ -51,8 +51,16 @@ mod tests;
51
51
///
52
52
/// Going above this limit will abort your program (although not
53
53
/// 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`.
54
59
const MAX_REFCOUNT : usize = ( isize:: MAX ) as usize ;
55
60
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
+
56
64
#[ cfg( not( sanitize = "thread" ) ) ]
57
65
macro_rules! acquire {
58
66
( $x: expr) => {
@@ -1104,6 +1112,9 @@ impl<T: ?Sized> Arc<T> {
1104
1112
continue ;
1105
1113
}
1106
1114
1115
+ // We can't allow the refcount to increase much past `MAX_REFCOUNT`.
1116
+ assert ! ( cur <= MAX_REFCOUNT , "{}" , INTERNAL_OVERFLOW_ERROR ) ;
1117
+
1107
1118
// NOTE: this code currently ignores the possibility of overflow
1108
1119
// into usize::MAX; in general both Rc and Arc need to be adjusted
1109
1120
// to deal with overflow.
@@ -1519,6 +1530,11 @@ impl<T: ?Sized> Clone for Arc<T> {
1519
1530
// the worst already happened and we actually do overflow the `usize` counter. However, that
1520
1531
// requires the counter to grow from `isize::MAX` to `usize::MAX` between the increment
1521
1532
// 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.
1522
1538
if old_size > MAX_REFCOUNT {
1523
1539
abort ( ) ;
1524
1540
}
@@ -2180,9 +2196,7 @@ impl<T: ?Sized> Weak<T> {
2180
2196
return None ;
2181
2197
}
2182
2198
// 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 ) ;
2186
2200
Some ( n + 1 )
2187
2201
} )
2188
2202
. ok ( )
0 commit comments