diff options
| author | Michael Goulet <michael@errs.io> | 2022-06-23 14:39:13 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-06-23 14:39:13 -0700 |
| commit | e749ba20616de16d0643d1dd2155bd32fd02d51f (patch) | |
| tree | 1c975054dffcf8e03cf133eb1c28649d1751ac47 /library/alloc | |
| parent | cc45ad50f8aea40f0d3b137d86b509f42c19f96c (diff) | |
| parent | 46b2454bad71b844ef5eb40860fb50131b6fe168 (diff) | |
| download | rust-e749ba20616de16d0643d1dd2155bd32fd02d51f.tar.gz rust-e749ba20616de16d0643d1dd2155bd32fd02d51f.zip | |
Rollup merge of #98364 - RalfJung:arc-clone, r=Mark-Simulacrum
clarify Arc::clone overflow check comment I had to read this twice to realize that this is explaining that the code is technically unsound, so move that into a dedicated paragraph and make the wording a bit more explicit.
Diffstat (limited to 'library/alloc')
| -rw-r--r-- | library/alloc/src/sync.rs | 17 |
1 files changed, 9 insertions, 8 deletions
diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 2670b15982a..24e849aab4c 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -1355,15 +1355,16 @@ impl<T: ?Sized> Clone for Arc<T> { // [1]: (www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html) let old_size = self.inner().strong.fetch_add(1, Relaxed); - // However we need to guard against massive refcounts in case someone - // is `mem::forget`ing Arcs. If we don't do this the count can overflow - // and users will use-after free. We racily saturate to `isize::MAX` on - // the assumption that there aren't ~2 billion threads incrementing - // the reference count at once. This branch will never be taken in - // any realistic program. + // However we need to guard against massive refcounts in case someone is `mem::forget`ing + // Arcs. If we don't do this the count can overflow and users will use-after free. This + // branch will never be taken in any realistic program. We abort because such a program is + // incredibly degenerate, and we don't care to support it. // - // We abort because such a program is incredibly degenerate, and we - // don't care to support it. + // This check is not 100% water-proof: we error when the refcount grows beyond `isize::MAX`. + // But we do that check *after* having done the increment, so there is a chance here that + // 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. if old_size > MAX_REFCOUNT { abort(); } |
