diff options
| author | Sebastian Dröge <sebastian@centricular.com> | 2021-10-10 21:02:42 +0300 |
|---|---|---|
| committer | Sebastian Dröge <sebastian@centricular.com> | 2021-10-10 21:13:39 +0300 |
| commit | 2e2c38e59be7d0308c8a58c0843e7af8d7211ee7 (patch) | |
| tree | 31dcedc218004f0a08258940679967a34de3d623 /library/alloc/src/rc.rs | |
| parent | 0c87288f92b7e6365d61cfbcbc453ea4c696c030 (diff) | |
| download | rust-2e2c38e59be7d0308c8a58c0843e7af8d7211ee7.tar.gz rust-2e2c38e59be7d0308c8a58c0843e7af8d7211ee7.zip | |
Mark `Arc::from_inner` / `Rc::from_inner` as unsafe
While it's an internal function, it is easy to create invalid Arc/Rcs to a dangling pointer with it. Fixes https://github.com/rust-lang/rust/issues/89740
Diffstat (limited to 'library/alloc/src/rc.rs')
| -rw-r--r-- | library/alloc/src/rc.rs | 51 |
1 files changed, 31 insertions, 20 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 81e97805a72..eff20efccc8 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -333,12 +333,12 @@ impl<T: ?Sized> Rc<T> { unsafe { self.ptr.as_ref() } } - fn from_inner(ptr: NonNull<RcBox<T>>) -> Self { + unsafe fn from_inner(ptr: NonNull<RcBox<T>>) -> Self { Self { ptr, phantom: PhantomData } } unsafe fn from_ptr(ptr: *mut RcBox<T>) -> Self { - Self::from_inner(unsafe { NonNull::new_unchecked(ptr) }) + unsafe { Self::from_inner(NonNull::new_unchecked(ptr)) } } } @@ -359,9 +359,11 @@ impl<T> Rc<T> { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - Self::from_inner( - Box::leak(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value }).into(), - ) + unsafe { + Self::from_inner( + Box::leak(box RcBox { strong: Cell::new(1), weak: Cell::new(1), value }).into(), + ) + } } /// Constructs a new `Rc<T>` using a weak reference to itself. Attempting @@ -412,16 +414,16 @@ impl<T> Rc<T> { // otherwise. let data = data_fn(&weak); - unsafe { + let strong = unsafe { let inner = init_ptr.as_ptr(); ptr::write(ptr::addr_of_mut!((*inner).value), data); let prev_value = (*inner).strong.get(); debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); (*inner).strong.set(1); - } - let strong = Rc::from_inner(init_ptr); + Rc::from_inner(init_ptr) + }; // Strong references should collectively own a shared weak reference, // so don't run the destructor for our old weak reference. @@ -511,10 +513,12 @@ impl<T> Rc<T> { // pointers, which ensures that the weak destructor never frees // the allocation while the strong destructor is running, even // if the weak pointer is stored inside the strong one. - Ok(Self::from_inner( - Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?) - .into(), - )) + unsafe { + Ok(Self::from_inner( + Box::leak(Box::try_new(RcBox { strong: Cell::new(1), weak: Cell::new(1), value })?) + .into(), + )) + } } /// Constructs a new `Rc` with uninitialized contents, returning an error if the allocation fails @@ -733,7 +737,7 @@ impl<T> Rc<mem::MaybeUninit<T>> { #[unstable(feature = "new_uninit", issue = "63291")] #[inline] pub unsafe fn assume_init(self) -> Rc<T> { - Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) + unsafe { Rc::from_inner(mem::ManuallyDrop::new(self).ptr.cast()) } } } @@ -1199,9 +1203,11 @@ impl Rc<dyn Any> { /// ``` pub fn downcast<T: Any>(self) -> Result<Rc<T>, Rc<dyn Any>> { if (*self).is::<T>() { - let ptr = self.ptr.cast::<RcBox<T>>(); - forget(self); - Ok(Rc::from_inner(ptr)) + unsafe { + let ptr = self.ptr.cast::<RcBox<T>>(); + forget(self); + Ok(Rc::from_inner(ptr)) + } } else { Err(self) } @@ -1474,8 +1480,10 @@ impl<T: ?Sized> Clone for Rc<T> { /// ``` #[inline] fn clone(&self) -> Rc<T> { - self.inner().inc_strong(); - Self::from_inner(self.ptr) + unsafe { + self.inner().inc_strong(); + Self::from_inner(self.ptr) + } } } @@ -2225,11 +2233,14 @@ impl<T: ?Sized> Weak<T> { #[stable(feature = "rc_weak", since = "1.4.0")] pub fn upgrade(&self) -> Option<Rc<T>> { let inner = self.inner()?; + if inner.strong() == 0 { None } else { - inner.inc_strong(); - Some(Rc::from_inner(self.ptr)) + unsafe { + inner.inc_strong(); + Some(Rc::from_inner(self.ptr)) + } } } |
