Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions library/alloc/src/alloc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,7 @@ pub struct Global;
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn alloc(layout: Layout) -> *mut u8 {
// SAFETY: Upheld by caller.
unsafe {
// Make sure we don't accidentally allow omitting the allocator shim in
// stable code until it is actually stabilized.
Expand Down Expand Up @@ -159,13 +160,15 @@ pub unsafe fn alloc(layout: Layout) -> *mut u8 {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
// SAFETY: Upheld by caller.
unsafe { dealloc_nonnull(NonNull::new_unchecked(ptr), layout) }
}

/// Same as [`dealloc`] but when you already have a non-null pointer
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn dealloc_nonnull(ptr: NonNull<u8>, layout: Layout) {
// SAFETY: Upheld by caller.
unsafe { __rust_dealloc(ptr, layout.size(), layout.alignment()) }
}

Expand Down Expand Up @@ -212,13 +215,15 @@ unsafe fn dealloc_nonnull(ptr: NonNull<u8>, layout: Layout) {
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
// SAFETY: Upheld by caller.
unsafe { realloc_nonnull(NonNull::new_unchecked(ptr), layout, new_size) }
}

/// Same as [`realloc`] but when you already have a non-null pointer
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
unsafe fn realloc_nonnull(ptr: NonNull<u8>, layout: Layout, new_size: usize) -> *mut u8 {
// SAFETY: Upheld by caller.
unsafe { __rust_realloc(ptr, layout.size(), layout.alignment(), new_size) }
}

Expand Down Expand Up @@ -276,6 +281,7 @@ unsafe fn realloc_nonnull(ptr: NonNull<u8>, layout: Layout, new_size: usize) ->
#[inline]
#[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces
pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
// SAFETY: Upheld by caller.
Comment thread
nia-e marked this conversation as resolved.
unsafe {
// Make sure we don't accidentally allow omitting the allocator shim in
// stable code until it is actually stabilized.
Expand Down Expand Up @@ -519,6 +525,7 @@ impl Global {
cmp::min(old_layout.size(), new_layout.size()),
);
}
// SAFETY: Caller ensures the ptr & layout are correct.
unsafe {
self.deallocate_impl(ptr, old_layout);
}
Expand Down Expand Up @@ -633,6 +640,7 @@ pub const fn handle_alloc_error(layout: Layout) -> ! {

#[inline]
fn rt_error(layout: Layout) -> ! {
// SAFETY: Safe to call; we control this function.
Comment thread
nia-e marked this conversation as resolved.
unsafe {
__rust_alloc_error_handler(layout.size(), layout.align());
}
Expand Down
67 changes: 48 additions & 19 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,8 @@ const fn box_new_uninit(layout: Layout) -> *mut u8 {
pub const fn box_assume_init_into_vec_unsafe<T, const N: usize>(
b: Box<MaybeUninit<[T; N]>>,
) -> crate::vec::Vec<T> {
// SAFETY: Technically not, but this can't be
// called stably except in ways we control.
unsafe { (b.assume_init() as Box<[T]>).into_vec() }
}

Expand Down Expand Up @@ -450,6 +452,7 @@ impl<T> Box<T> {
if size_of::<T>() == size_of::<U>() && align_of::<T>() == align_of::<U>() {
let (value, allocation) = Box::take(this);
Box::write(
// SAFETY: Untriaged.
unsafe { mem::transmute::<Box<MaybeUninit<T>>, Box<MaybeUninit<U>>>(allocation) },
f(value),
)
Expand Down Expand Up @@ -490,6 +493,7 @@ impl<T> Box<T> {
let (value, allocation) = Box::take(this);
try {
Box::write(
// SAFETY: Untriaged.
unsafe {
mem::transmute::<Box<MaybeUninit<T>>, Box<MaybeUninit<R::Output>>>(
allocation,
Expand Down Expand Up @@ -528,6 +532,7 @@ impl<T, A: Allocator> Box<T, A> {
{
let mut boxed = Self::new_uninit_in(alloc);
boxed.write(x);
// SAFETY: Initialised by the above.
unsafe { boxed.assume_init() }
}

Expand All @@ -554,6 +559,7 @@ impl<T, A: Allocator> Box<T, A> {
{
let mut boxed = Self::try_new_uninit_in(alloc)?;
boxed.write(x);
// SAFETY: Initialised by the above.
unsafe { Ok(boxed.assume_init()) }
}

Expand Down Expand Up @@ -618,6 +624,7 @@ impl<T, A: Allocator> Box<T, A> {
let layout = Layout::new::<mem::MaybeUninit<T>>();
alloc.allocate(layout)?.cast()
};
// SAFETY: Pointer is nonnull and matches the allocator.
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
}

Expand Down Expand Up @@ -690,6 +697,7 @@ impl<T, A: Allocator> Box<T, A> {
let layout = Layout::new::<mem::MaybeUninit<T>>();
alloc.allocate_zeroed(layout)?.cast()
};
// SAFETY: Pointer is nonnull and matches the allocator.
unsafe { Ok(Box::from_raw_in(ptr.as_ptr(), alloc)) }
}

Expand Down Expand Up @@ -726,6 +734,7 @@ impl<T, A: Allocator> Box<T, A> {
#[unstable(feature = "box_into_boxed_slice", issue = "71582")]
pub fn into_boxed_slice(boxed: Self) -> Box<[T], A> {
let (raw, alloc) = Box::into_raw_with_allocator(boxed);
// SAFETY: A pointer to T is also a valid pointer to [T; 1].
unsafe { Box::from_raw_in(raw as *mut [T; 1], alloc) }
}

Expand Down Expand Up @@ -769,6 +778,8 @@ impl<T, A: Allocator> Box<T, A> {
/// ```
#[unstable(feature = "box_take", issue = "147212")]
pub fn take(boxed: Self) -> (T, Box<mem::MaybeUninit<T>, A>) {
// SAFETY: Reading out an initialised value & leaving behind a
// box with uninit contents.
unsafe {
let (raw, alloc) = Box::into_non_null_with_allocator(boxed);
let value = raw.read();
Expand Down Expand Up @@ -872,7 +883,7 @@ impl<T: ?Sized + CloneToUninit, A: Allocator> Box<T, A> {
impl<'a, A: Allocator> Drop for DeallocDropGuard<'a, A> {
fn drop(&mut self) {
let &mut DeallocDropGuard(layout, alloc, ptr) = self;
// Safety: `ptr` was allocated by `*alloc` with layout `layout`
// SAFETY: `ptr` was allocated by `*alloc` with layout `layout`
unsafe {
alloc.deallocate(ptr, layout);
}
Expand All @@ -887,15 +898,15 @@ impl<T: ?Sized + CloneToUninit, A: Allocator> Box<T, A> {
(ptr, Some(DeallocDropGuard(layout, &alloc, ptr)))
};
let ptr = ptr.as_ptr();
// Safety: `*ptr` is newly allocated, correctly aligned to `align_of_val(src)`,
// SAFETY: `*ptr` is newly allocated, correctly aligned to `align_of_val(src)`,
// and is valid for writes for `size_of_val(src)`.
// If this panics, then `guard` will deallocate for us (if allocation occuured)
unsafe {
<T as CloneToUninit>::clone_to_uninit(src, ptr);
}
// Defuse the deallocate guard
core::mem::forget(guard);
// Safety: We just initialized `*ptr` as a clone of `src`
// SAFETY: We just initialized `*ptr` as a clone of `src`
Ok(unsafe { Box::from_raw_in(ptr.with_metadata_of(src), alloc) })
}
}
Expand All @@ -919,6 +930,7 @@ impl<T> Box<[T]> {
#[stable(feature = "new_uninit", since = "1.82.0")]
#[must_use]
pub fn new_uninit_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
// SAFETY: Untriaged.
unsafe { RawVec::with_capacity(len).into_box(len) }
}

Expand All @@ -942,6 +954,7 @@ impl<T> Box<[T]> {
#[stable(feature = "new_zeroed_alloc", since = "1.92.0")]
#[must_use]
pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit<T>]> {
// SAFETY: Untriaged.
unsafe { RawVec::with_capacity_zeroed(len).into_box(len) }
}

Expand Down Expand Up @@ -975,6 +988,7 @@ impl<T> Box<[T]> {
};
Global.allocate(layout)?.cast()
};
// SAFETY: Untriaged.
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
}

Expand Down Expand Up @@ -1009,6 +1023,7 @@ impl<T> Box<[T]> {
};
Global.allocate_zeroed(layout)?.cast()
};
// SAFETY: Untriaged.
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, Global).into_box(len)) }
}
}
Expand Down Expand Up @@ -1036,6 +1051,7 @@ impl<T, A: Allocator> Box<[T], A> {
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
pub fn new_uninit_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
// SAFETY: Untriaged.
unsafe { RawVec::with_capacity_in(len, alloc).into_box(len) }
}

Expand Down Expand Up @@ -1063,6 +1079,7 @@ impl<T, A: Allocator> Box<[T], A> {
#[unstable(feature = "allocator_api", issue = "32838")]
#[must_use]
pub fn new_zeroed_slice_in(len: usize, alloc: A) -> Box<[mem::MaybeUninit<T>], A> {
// SAFETY: Untriaged.
unsafe { RawVec::with_capacity_zeroed_in(len, alloc).into_box(len) }
}

Expand Down Expand Up @@ -1101,6 +1118,7 @@ impl<T, A: Allocator> Box<[T], A> {
};
alloc.allocate(layout)?.cast()
};
// SAFETY: Untriaged.
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) }
}

Expand Down Expand Up @@ -1140,6 +1158,7 @@ impl<T, A: Allocator> Box<[T], A> {
};
alloc.allocate_zeroed(layout)?.cast()
};
// SAFETY: Untriaged.
unsafe { Ok(RawVec::from_raw_parts_in(ptr.as_ptr(), len, alloc).into_box(len)) }
}

Expand Down Expand Up @@ -1237,6 +1256,7 @@ impl<T, A: Allocator> Box<mem::MaybeUninit<T>, A> {
#[stable(feature = "box_uninit_write", since = "1.87.0")]
#[inline]
pub fn write(mut boxed: Self, value: T) -> Box<T, A> {
// SAFETY: Writing initialises the boxed value.
unsafe {
(*boxed).write(value);
boxed.assume_init()
Expand Down Expand Up @@ -1273,6 +1293,7 @@ impl<T, A: Allocator> Box<[mem::MaybeUninit<T>], A> {
#[inline]
pub unsafe fn assume_init(self) -> Box<[T], A> {
let (raw, alloc) = Box::into_raw_with_allocator(self);
// SAFETY: Upheld by caller.
unsafe { Box::from_raw_in(raw as *mut [T], alloc) }
}
}
Expand Down Expand Up @@ -1326,6 +1347,7 @@ impl<T: ?Sized> Box<T> {
#[inline]
#[must_use = "call `drop(Box::from_raw(ptr))` if you intend to drop the `Box`"]
pub unsafe fn from_raw(raw: *mut T) -> Self {
// SAFETY: Upheld by caller.
unsafe { Self::from_raw_in(raw, Global) }
}

Expand Down Expand Up @@ -1378,6 +1400,7 @@ impl<T: ?Sized> Box<T> {
#[inline]
#[must_use = "call `drop(Box::from_non_null(ptr))` if you intend to drop the `Box`"]
pub unsafe fn from_non_null(ptr: NonNull<T>) -> Self {
// SAFETY: Upheld by caller.
unsafe { Self::from_raw(ptr.as_ptr()) }
}

Expand Down Expand Up @@ -1557,6 +1580,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
#[unstable(feature = "allocator_api", issue = "32838")]
#[inline]
pub unsafe fn from_raw_in(raw: *mut T, alloc: A) -> Self {
// SAFETY: Upheld by caller.
Box(unsafe { Unique::new_unchecked(raw) }, alloc)
}

Expand Down Expand Up @@ -1675,6 +1699,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
// In case `A` *is* `Global`, this does not quite have the right behavior; `into_raw`
// works around that.
let ptr = &raw mut **b;
// SAFETY: See above.
let alloc = unsafe { ptr::read(&b.1) };
(ptr, alloc)
}
Expand Down Expand Up @@ -1742,6 +1767,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
#[doc(hidden)]
pub fn into_unique(b: Self) -> (Unique<T>, A) {
let (ptr, alloc) = Box::into_raw_with_allocator(b);
// SAFETY: Pointer is valid and unique.
unsafe { (Unique::from(&mut *ptr), alloc) }
}

Expand Down Expand Up @@ -1940,6 +1966,7 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
{
let (ptr, alloc) = Box::into_raw_with_allocator(b);
mem::forget(alloc);
// SAFETY: Pointer is valid and unique.
unsafe { &mut *ptr }
}

Expand Down Expand Up @@ -1978,9 +2005,9 @@ impl<T: ?Sized, A: Allocator> Box<T, A> {
where
A: 'static,
{
// It's not possible to move or replace the insides of a `Pin<Box<T>>`
// when `T: !Unpin`, so it's safe to pin it directly without any
// additional requirements.
// SAFETY: It's not possible to move or replace the insides of a
// `Pin<Box<T>>` when `T: !Unpin`, so it's safe to pin it directly
// without any additional requirements.
unsafe { Pin::new_unchecked(boxed) }
}
}
Expand All @@ -1993,6 +2020,7 @@ unsafe impl<#[may_dangle] T: ?Sized, A: Allocator> Drop for Box<T, A> {

let ptr = self.0;

// SAFETY: Untriaged.
unsafe {
let layout = Layout::for_value_raw(ptr.as_ptr());
if layout.size() != 0 {
Expand All @@ -2009,19 +2037,18 @@ impl<T: Default> Default for Box<T> {
#[inline]
fn default() -> Self {
let mut x: Box<mem::MaybeUninit<T>> = Box::new_uninit();
unsafe {
// SAFETY: `x` is valid for writing and has the same layout as `T`.
// If `T::default()` panics, dropping `x` will just deallocate the Box as `MaybeUninit<T>`
// does not have a destructor.
//
// We use `ptr::write` as `MaybeUninit::write` creates
// extra stack copies of `T` in debug mode.
//
// See https://github.com/rust-lang/rust/issues/136043 for more context.
ptr::write(&raw mut *x as *mut T, T::default());
// SAFETY: `x` was just initialized above.
x.assume_init()
}

// SAFETY: `x` is valid for writing and has the same layout as `T`.
// If `T::default()` panics, dropping `x` will just deallocate the Box as `MaybeUninit<T>`
// does not have a destructor.
//
// We use `ptr::write` as `MaybeUninit::write` creates
// extra stack copies of `T` in debug mode.
//
// See https://github.com/rust-lang/rust/issues/136043 for more context.
unsafe { ptr::write(&raw mut *x as *mut T, T::default()) };
// SAFETY: `x` was just initialized above.
unsafe { x.assume_init() }
}
}

Expand Down Expand Up @@ -2084,6 +2111,7 @@ impl<T: Clone, A: Allocator + Clone> Clone for Box<T, A> {
fn clone(&self) -> Self {
// Pre-allocate memory to allow writing the cloned value directly.
let mut boxed = Self::new_uninit_in(self.1.clone());
// SAFETY: Destination pointer is valid and will then become initialised.
unsafe {
(**self).clone_to_uninit(boxed.as_mut_ptr().cast());
boxed.assume_init()
Expand Down Expand Up @@ -2154,6 +2182,7 @@ impl Clone for Box<str> {
fn clone(&self) -> Self {
// this makes a copy of the data
let buf: Box<[u8]> = self.as_bytes().into();
// SAFETY: We know the [u8] is a valid str.
unsafe { from_boxed_utf8_unchecked(buf) }
}
}
Expand Down
Loading
Loading