Skip to content

Commit 8f43fa0

Browse files
committed
Add WeakInner<'_> and have Weak::inner() return it
This avoids overlapping a reference covering the data field, which may be changed due in concurrent conditions. This fully fixed the UB mainfested with `new_cyclic`.
1 parent 493c037 commit 8f43fa0

File tree

1 file changed

+70
-39
lines changed

1 file changed

+70
-39
lines changed

library/alloc/src/rc.rs

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -469,7 +469,7 @@ impl<T> Rc<T> {
469469
// the strong count, and then remove the implicit "strong weak"
470470
// pointer while also handling drop logic by just crafting a
471471
// fake Weak.
472-
this.dec_strong();
472+
this.inner().dec_strong();
473473
let _weak = Weak { ptr: this.ptr };
474474
forget(this);
475475
Ok(val)
@@ -735,7 +735,7 @@ impl<T: ?Sized> Rc<T> {
735735
/// ```
736736
#[stable(feature = "rc_weak", since = "1.4.0")]
737737
pub fn downgrade(this: &Self) -> Weak<T> {
738-
this.inc_weak();
738+
this.inner().inc_weak();
739739
// Make sure we do not create a dangling Weak
740740
debug_assert!(!is_dangling(this.ptr));
741741
Weak { ptr: this.ptr }
@@ -756,7 +756,7 @@ impl<T: ?Sized> Rc<T> {
756756
#[inline]
757757
#[stable(feature = "rc_counts", since = "1.15.0")]
758758
pub fn weak_count(this: &Self) -> usize {
759-
this.weak() - 1
759+
this.inner().weak() - 1
760760
}
761761

762762
/// Gets the number of strong (`Rc`) pointers to this allocation.
@@ -774,7 +774,7 @@ impl<T: ?Sized> Rc<T> {
774774
#[inline]
775775
#[stable(feature = "rc_counts", since = "1.15.0")]
776776
pub fn strong_count(this: &Self) -> usize {
777-
this.strong()
777+
this.inner().strong()
778778
}
779779

780780
/// Returns `true` if there are no other `Rc` or [`Weak`] pointers to
@@ -844,7 +844,16 @@ impl<T: ?Sized> Rc<T> {
844844
#[inline]
845845
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
846846
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
847-
unsafe { &mut this.ptr.as_mut().value }
847+
// We are careful to *not* create a reference covering the "count" fields, as
848+
// this would alias with reenterant access to the reference counts (e.g. by `Weak`).
849+
unsafe { &mut (*this.ptr.as_ptr()).value }
850+
}
851+
852+
#[inline]
853+
fn inner(&self) -> &RcBox<T> {
854+
// This unsafety is ok because while this Rc is alive we're guaranteed
855+
// that the inner pointer is valid.
856+
unsafe { self.ptr.as_ref() }
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
11981207
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,30 @@ 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> {
2121-
#[inline(always)]
2122-
fn inner(&self) -> &RcBox<T> {
2123-
unsafe { self.ptr.as_ref() }
2147+
impl <T: ?Sized> RcInnerPtr for RcBox<T> {
2148+
fn weak_ref(&self) -> &Cell<usize> {
2149+
&self.weak
2150+
}
2151+
fn strong_ref(&self) -> &Cell<usize> {
2152+
&self.strong
21242153
}
21252154
}
21262155

2127-
impl<T: ?Sized> RcBoxPtr<T> for RcBox<T> {
2128-
#[inline(always)]
2129-
fn inner(&self) -> &RcBox<T> {
2130-
self
2156+
impl<'a> RcInnerPtr for WeakInner<'a> {
2157+
fn weak_ref(&self) -> &Cell<usize> {
2158+
self.weak
2159+
}
2160+
fn strong_ref(&self) -> &Cell<usize> {
2161+
self.strong
21312162
}
21322163
}
21332164

0 commit comments

Comments
 (0)