Skip to content

Commit 1610447

Browse files
committed
clarify documentation about the memory layout of UnsafeCell
1 parent cb94675 commit 1610447

File tree

1 file changed

+34
-25
lines changed

1 file changed

+34
-25
lines changed

library/core/src/cell.rs

+34-25
Original file line numberDiff line numberDiff line change
@@ -1825,35 +1825,44 @@ impl<T: ?Sized + fmt::Display> fmt::Display for RefMut<'_, T> {
18251825
/// Therefore this is not a valid conversion, despite `NonNull<u8>` and `UnsafeCell<NonNull<u8>>>`
18261826
/// having the same memory layout. This is because `UnsafeCell` disables niche optimizations in
18271827
/// order to avoid its interior mutability property from spreading from `T` into the `Outer` type,
1828-
/// thus this can cause distortions in the type size in these cases. Furthermore, it is only valid
1829-
/// to obtain a `*mut T` pointer to the contents of a _shared_ `UnsafeCell<T>` through [`.get()`]
1830-
/// or [`.raw_get()`]. A `&mut T` reference can be obtained by either dereferencing this pointer or
1831-
/// by calling [`.get_mut()`] on an _exclusive_ `UnsafeCell<T>`, e.g.:
1828+
/// thus this can cause distortions in the type size in these cases.
1829+
///
1830+
/// Note that it is still only valid to obtain a `*mut T` pointer to the contents of a
1831+
/// _shared_ `UnsafeCell<T>` through [`.get()`] or [`.raw_get()`]. A `&mut T` reference
1832+
/// can be obtained by either dereferencing this pointer or by calling [`.get_mut()`]
1833+
/// on an _exclusive_ `UnsafeCell<T>`. Even though `T` and `UnsafeCell<T>` have the
1834+
/// same memory layout, the following is not allowed and undefined behavior:
1835+
///
1836+
/// ```rust,no_run
1837+
/// # use std::cell::UnsafeCell;
1838+
/// unsafe fn not_allowed<T>(ptr: &UnsafeCell<T>) -> &mut T {
1839+
/// let t = ptr as *const UnsafeCell<T> as *mut T;
1840+
/// // This is undefined behavior, because the `*mut T` pointer
1841+
/// // was not obtained through `.get()` nor `.raw_get()`:
1842+
/// unsafe { &mut *t }
1843+
/// }
1844+
/// ```
1845+
///
1846+
/// Instead, do this:
18321847
///
18331848
/// ```rust
1834-
/// use std::cell::UnsafeCell;
1849+
/// # use std::cell::UnsafeCell;
1850+
/// // Safety: the caller must ensure that there are no references that
1851+
/// // point to the *contents* of the `UnsafeCell`.
1852+
/// unsafe fn get_mut<T>(ptr: &UnsafeCell<T>) -> &mut T {
1853+
/// unsafe { &mut *ptr.get() }
1854+
/// }
1855+
/// ```
18351856
///
1836-
/// let mut x: UnsafeCell<u32> = UnsafeCell::new(5);
1837-
/// let shared: &UnsafeCell<u32> = &x;
1838-
/// // using `.get()` is okay:
1839-
/// unsafe {
1840-
/// // SAFETY: there exist no other references to the contents of `x`
1841-
/// let exclusive: &mut u32 = &mut *shared.get();
1842-
/// };
1843-
/// // using `.raw_get()` is also okay:
1844-
/// unsafe {
1845-
/// // SAFETY: there exist no other references to the contents of `x` in this scope
1846-
/// let exclusive: &mut u32 = &mut *UnsafeCell::raw_get(shared as *const _);
1847-
/// };
1848-
/// // using `.get_mut()` is always safe:
1849-
/// let exclusive: &mut u32 = x.get_mut();
1857+
/// Coverting in the other direction from a `&mut T`
1858+
/// to an `&UnsafeCell<T>` is allowed:
18501859
///
1851-
/// // when we have exclusive access, we can convert it to a shared `&UnsafeCell`:
1852-
/// unsafe {
1853-
/// // SAFETY: `u32` has no niche, therefore it has the same layout as `UnsafeCell<u32>`
1854-
/// let shared: &UnsafeCell<u32> = &*(exclusive as *mut _ as *const UnsafeCell<u32>);
1855-
/// // SAFETY: there exist no other *active* references to the contents of `x` in this scope
1856-
/// let exclusive: &mut u32 = &mut *shared.get();
1860+
/// ```rust
1861+
/// # use std::cell::UnsafeCell;
1862+
/// fn get_shared<T>(ptr: &mut T) -> &UnsafeCell<T> {
1863+
/// let t = ptr as *mut T as *const UnsafeCell<T>;
1864+
/// // SAFETY: `T` and `UnsafeCell<T>` have the same memory layout
1865+
/// unsafe { &*t }
18571866
/// }
18581867
/// ```
18591868
///

0 commit comments

Comments
 (0)