summaryrefslogtreecommitdiffstats
path: root/library/alloc/src/rc.rs
diff options
context:
space:
mode:
Diffstat (limited to 'library/alloc/src/rc.rs')
-rw-r--r--library/alloc/src/rc.rs66
1 files changed, 49 insertions, 17 deletions
diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs
index 006d813e5..38e31b180 100644
--- a/library/alloc/src/rc.rs
+++ b/library/alloc/src/rc.rs
@@ -293,6 +293,15 @@ struct RcBox<T: ?Sized> {
value: T,
}
+/// Calculate layout for `RcBox<T>` using the inner value's layout
+fn rcbox_layout_for_value_layout(layout: Layout) -> Layout {
+ // Calculate layout using the given value layout.
+ // Previously, layout was calculated on the expression
+ // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
+ // reference (see #54908).
+ Layout::new::<RcBox<()>>().extend(layout).unwrap().0.pad_to_align()
+}
+
/// A single-threaded reference-counting pointer. 'Rc' stands for 'Reference
/// Counted'.
///
@@ -1082,10 +1091,11 @@ impl<T: ?Sized> Rc<T> {
///
/// # Safety
///
- /// Any other `Rc` or [`Weak`] pointers to the same allocation must not be dereferenced
- /// for the duration of the returned borrow.
- /// This is trivially the case if no such pointers exist,
- /// for example immediately after `Rc::new`.
+ /// If any other `Rc` or [`Weak`] pointers to the same allocation exist, then
+ /// they must be must not be dereferenced or have active borrows for the duration
+ /// of the returned borrow, and their inner type must be exactly the same as the
+ /// inner type of this Rc (including lifetimes). This is trivially the case if no
+ /// such pointers exist, for example immediately after `Rc::new`.
///
/// # Examples
///
@@ -1100,6 +1110,38 @@ impl<T: ?Sized> Rc<T> {
/// }
/// assert_eq!(*x, "foo");
/// ```
+ /// Other `Rc` pointers to the same allocation must be to the same type.
+ /// ```no_run
+ /// #![feature(get_mut_unchecked)]
+ ///
+ /// use std::rc::Rc;
+ ///
+ /// let x: Rc<str> = Rc::from("Hello, world!");
+ /// let mut y: Rc<[u8]> = x.clone().into();
+ /// unsafe {
+ /// // this is Undefined Behavior, because x's inner type is str, not [u8]
+ /// Rc::get_mut_unchecked(&mut y).fill(0xff); // 0xff is invalid in UTF-8
+ /// }
+ /// println!("{}", &*x); // Invalid UTF-8 in a str
+ /// ```
+ /// Other `Rc` pointers to the same allocation must be to the exact same type, including lifetimes.
+ /// ```no_run
+ /// #![feature(get_mut_unchecked)]
+ ///
+ /// use std::rc::Rc;
+ ///
+ /// let x: Rc<&str> = Rc::new("Hello, world!");
+ /// {
+ /// let s = String::from("Oh, no!");
+ /// let mut y: Rc<&str> = x.clone().into();
+ /// unsafe {
+ /// // this is Undefined Behavior, because x's inner type
+ /// // is &'long str, not &'short str
+ /// *Rc::get_mut_unchecked(&mut y) = &s;
+ /// }
+ /// }
+ /// println!("{}", &*x); // Use-after-free
+ /// ```
#[inline]
#[unstable(feature = "get_mut_unchecked", issue = "63292")]
pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T {
@@ -1334,11 +1376,7 @@ impl<T: ?Sized> Rc<T> {
allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>,
) -> *mut RcBox<T> {
- // Calculate layout using the given value layout.
- // Previously, layout was calculated on the expression
- // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
- // reference (see #54908).
- let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
+ let layout = rcbox_layout_for_value_layout(value_layout);
unsafe {
Rc::try_allocate_for_layout(value_layout, allocate, mem_to_rcbox)
.unwrap_or_else(|_| handle_alloc_error(layout))
@@ -1357,11 +1395,7 @@ impl<T: ?Sized> Rc<T> {
allocate: impl FnOnce(Layout) -> Result<NonNull<[u8]>, AllocError>,
mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox<T>,
) -> Result<*mut RcBox<T>, AllocError> {
- // Calculate layout using the given value layout.
- // Previously, layout was calculated on the expression
- // `&*(ptr as *const RcBox<T>)`, but this created a misaligned
- // reference (see #54908).
- let layout = Layout::new::<RcBox<()>>().extend(value_layout).unwrap().0.pad_to_align();
+ let layout = rcbox_layout_for_value_layout(value_layout);
// Allocate for the layout.
let ptr = allocate(layout)?;
@@ -1428,7 +1462,7 @@ impl<T> Rc<[T]> {
}
}
- /// Copy elements from slice into newly allocated Rc<\[T\]>
+ /// Copy elements from slice into newly allocated `Rc<[T]>`
///
/// Unsafe because the caller must either take ownership or bind `T: Copy`
#[cfg(not(no_global_oom_handling))]
@@ -1968,10 +2002,8 @@ impl<T> From<Vec<T>> for Rc<[T]> {
fn from(mut v: Vec<T>) -> Rc<[T]> {
unsafe {
let rc = Rc::copy_from_slice(&v);
-
// Allow the Vec to free its memory, but not destroy its contents
v.set_len(0);
-
rc
}
}