Skip to content

Commit a49451c

Browse files
authored
Rollup merge of #76530 - carbotaniuman:fix-rc, r=RalfJung
Eliminate mut reference UB in Drop impl for Rc<T> This changes `self.ptr.as_mut()` with `get_mut_unchecked` which does not use an intermediate reference. Arc<T> already handled this case properly. Fixes #76509
2 parents c20356e + b729368 commit a49451c

File tree

1 file changed

+75
-38
lines changed

1 file changed

+75
-38
lines changed

library/alloc/src/rc.rs

+75-38
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<Rc<U>> for Rc<T> {}
295295
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Rc<U>> for Rc<T> {}
296296

297297
impl<T: ?Sized> Rc<T> {
298+
#[inline(always)]
299+
fn inner(&self) -> &RcBox<T> {
300+
// This unsafety is ok because while this Rc is alive we're guaranteed
301+
// that the inner pointer is valid.
302+
unsafe { self.ptr.as_ref() }
303+
}
304+
298305
fn from_inner(ptr: NonNull<RcBox<T>>) -> Self {
299306
Self { ptr, phantom: PhantomData }
300307
}
@@ -469,7 +476,7 @@ impl<T> Rc<T> {
469476
// the strong count, and then remove the implicit "strong weak"
470477
// pointer while also handling drop logic by just crafting a
471478
// fake Weak.
472-
this.dec_strong();
479+
this.inner().dec_strong();
473480
let _weak = Weak { ptr: this.ptr };
474481
forget(this);
475482
Ok(val)
@@ -735,7 +742,7 @@ impl<T: ?Sized> Rc<T> {
735742
/// ```
736743
#[stable(feature = "rc_weak", since = "1.4.0")]
737744
pub fn downgrade(this: &Self) -> Weak<T> {
738-
this.inc_weak();
745+
this.inner().inc_weak();
739746
// Make sure we do not create a dangling Weak
740747
debug_assert!(!is_dangling(this.ptr));
741748
Weak { ptr: this.ptr }
@@ -756,7 +763,7 @@ impl<T: ?Sized> Rc<T> {
756763
#[inline]
757764
#[stable(feature = "rc_counts", since = "1.15.0")]
758765
pub fn weak_count(this: &Self) -> usize {
759-
this.weak() - 1
766+
this.inner().weak() - 1
760767
}
761768

762769
/// Gets the number of strong (`Rc`) pointers to this allocation.
@@ -774,7 +781,7 @@ impl<T: ?Sized> Rc<T> {
774781
#[inline]
775782
#[stable(feature = "rc_counts", since = "1.15.0")]
776783
pub fn strong_count(this: &Self) -> usize {
777-
this.strong()
784+
this.inner().strong()
778785
}
779786

780787
/// Returns `true` if there are no other `Rc` or [`Weak`] pointers to
@@ -844,7 +851,9 @@ impl<T: ?Sized> Rc<T> {
844851
#[inline]
845852
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
846853
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
847-
unsafe { &mut this.ptr.as_mut().value }
854+
// We are careful to *not* create a reference covering the "count" fields, as
855+
// this would conflict with accesses to the reference counts (e.g. by `Weak`).
856+
unsafe { &mut (*this.ptr.as_ptr()).value }
848857
}
849858

850859
#[inline]
@@ -931,10 +940,10 @@ impl<T: Clone> Rc<T> {
931940
unsafe {
932941
let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value));
933942
mem::swap(this, &mut swap);
934-
swap.dec_strong();
943+
swap.inner().dec_strong();
935944
// Remove implicit strong-weak ref (no need to craft a fake
936945
// Weak here -- we know other Weaks can clean up for us)
937-
swap.dec_weak();
946+
swap.inner().dec_weak();
938947
forget(swap);
939948
}
940949
}
@@ -1192,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc<T> {
11921201
/// ```
11931202
fn drop(&mut self) {
11941203
unsafe {
1195-
self.dec_strong();
1196-
if self.strong() == 0 {
1204+
self.inner().dec_strong();
1205+
if self.inner().strong() == 0 {
11971206
// destroy the contained object
1198-
ptr::drop_in_place(self.ptr.as_mut());
1207+
ptr::drop_in_place(Self::get_mut_unchecked(self));
11991208

12001209
// remove the implicit "strong weak" pointer now that we've
12011210
// destroyed the contents.
1202-
self.dec_weak();
1211+
self.inner().dec_weak();
12031212

1204-
if self.weak() == 0 {
1213+
if self.inner().weak() == 0 {
12051214
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
12061215
}
12071216
}
@@ -1227,7 +1236,7 @@ impl<T: ?Sized> Clone for Rc<T> {
12271236
/// ```
12281237
#[inline]
12291238
fn clone(&self) -> Rc<T> {
1230-
self.inc_strong();
1239+
self.inner().inc_strong();
12311240
Self::from_inner(self.ptr)
12321241
}
12331242
}
@@ -1851,6 +1860,13 @@ pub(crate) fn is_dangling<T: ?Sized>(ptr: NonNull<T>) -> bool {
18511860
address == usize::MAX
18521861
}
18531862

1863+
/// Helper type to allow accessing the reference counts without
1864+
/// making any assertions about the data field.
1865+
struct WeakInner<'a> {
1866+
weak: &'a Cell<usize>,
1867+
strong: &'a Cell<usize>,
1868+
}
1869+
18541870
impl<T: ?Sized> Weak<T> {
18551871
/// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying
18561872
/// dropping of the inner value if successful.
@@ -1910,11 +1926,21 @@ impl<T: ?Sized> Weak<T> {
19101926
.unwrap_or(0)
19111927
}
19121928

1913-
/// Returns `None` when the pointer is dangling and there is no allocated `RcBox`
1929+
/// Returns `None` when the pointer is dangling and there is no allocated `RcBox`,
19141930
/// (i.e., when this `Weak` was created by `Weak::new`).
19151931
#[inline]
1916-
fn inner(&self) -> Option<&RcBox<T>> {
1917-
if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) }
1932+
fn inner(&self) -> Option<WeakInner<'_>> {
1933+
if is_dangling(self.ptr) {
1934+
None
1935+
} else {
1936+
// We are careful to *not* create a reference covering the "data" field, as
1937+
// the field may be mutated concurrently (for example, if the last `Rc`
1938+
// is dropped, the data field will be dropped in-place).
1939+
Some(unsafe {
1940+
let ptr = self.ptr.as_ptr();
1941+
WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak }
1942+
})
1943+
}
19181944
}
19191945

19201946
/// Returns `true` if the two `Weak`s point to the same allocation (similar to
@@ -1992,14 +2018,14 @@ impl<T: ?Sized> Drop for Weak<T> {
19922018
/// assert!(other_weak_foo.upgrade().is_none());
19932019
/// ```
19942020
fn drop(&mut self) {
1995-
if let Some(inner) = self.inner() {
1996-
inner.dec_weak();
1997-
// the weak count starts at 1, and will only go to zero if all
1998-
// the strong pointers have disappeared.
1999-
if inner.weak() == 0 {
2000-
unsafe {
2001-
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
2002-
}
2021+
let inner = if let Some(inner) = self.inner() { inner } else { return };
2022+
2023+
inner.dec_weak();
2024+
// the weak count starts at 1, and will only go to zero if all
2025+
// the strong pointers have disappeared.
2026+
if inner.weak() == 0 {
2027+
unsafe {
2028+
Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref()));
20032029
}
20042030
}
20052031
}
@@ -2065,12 +2091,13 @@ impl<T> Default for Weak<T> {
20652091
// clone these much in Rust thanks to ownership and move-semantics.
20662092

20672093
#[doc(hidden)]
2068-
trait RcBoxPtr<T: ?Sized> {
2069-
fn inner(&self) -> &RcBox<T>;
2094+
trait RcInnerPtr {
2095+
fn weak_ref(&self) -> &Cell<usize>;
2096+
fn strong_ref(&self) -> &Cell<usize>;
20702097

20712098
#[inline]
20722099
fn strong(&self) -> usize {
2073-
self.inner().strong.get()
2100+
self.strong_ref().get()
20742101
}
20752102

20762103
#[inline]
@@ -2084,17 +2111,17 @@ trait RcBoxPtr<T: ?Sized> {
20842111
if strong == 0 || strong == usize::MAX {
20852112
abort();
20862113
}
2087-
self.inner().strong.set(strong + 1);
2114+
self.strong_ref().set(strong + 1);
20882115
}
20892116

20902117
#[inline]
20912118
fn dec_strong(&self) {
2092-
self.inner().strong.set(self.strong() - 1);
2119+
self.strong_ref().set(self.strong() - 1);
20932120
}
20942121

20952122
#[inline]
20962123
fn weak(&self) -> usize {
2097-
self.inner().weak.get()
2124+
self.weak_ref().get()
20982125
}
20992126

21002127
#[inline]
@@ -2108,26 +2135,36 @@ trait RcBoxPtr<T: ?Sized> {
21082135
if weak == 0 || weak == usize::MAX {
21092136
abort();
21102137
}
2111-
self.inner().weak.set(weak + 1);
2138+
self.weak_ref().set(weak + 1);
21122139
}
21132140

21142141
#[inline]
21152142
fn dec_weak(&self) {
2116-
self.inner().weak.set(self.weak() - 1);
2143+
self.weak_ref().set(self.weak() - 1);
21172144
}
21182145
}
21192146

2120-
impl<T: ?Sized> RcBoxPtr<T> for Rc<T> {
2147+
impl<T: ?Sized> RcInnerPtr for RcBox<T> {
21212148
#[inline(always)]
2122-
fn inner(&self) -> &RcBox<T> {
2123-
unsafe { self.ptr.as_ref() }
2149+
fn weak_ref(&self) -> &Cell<usize> {
2150+
&self.weak
2151+
}
2152+
2153+
#[inline(always)]
2154+
fn strong_ref(&self) -> &Cell<usize> {
2155+
&self.strong
21242156
}
21252157
}
21262158

2127-
impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
2159+
impl<'a> RcInnerPtr for WeakInner<'a> {
21282160
#[inline(always)]
2129-
fn inner(&self) -> &RcBox<T> {
2130-
self
2161+
fn weak_ref(&self) -> &Cell<usize> {
2162+
self.weak
2163+
}
2164+
2165+
#[inline(always)]
2166+
fn strong_ref(&self) -> &Cell<usize> {
2167+
self.strong
21312168
}
21322169
}
21332170

0 commit comments

Comments
 (0)