#[unstable(feature = "alloc_layout_extra", issue = "55724")]
#[inline]
pub fn repeat(&self, n: usize) -> Result<(Self, usize), LayoutErr> {
- // This cannot overflow. Quoting from the invariant of Layout:
- // > `size`, when rounded up to the nearest multiple of `align`,
- // > must not overflow (i.e., the rounded value must be less than
- // > `usize::MAX`)
- let padded_size = self.size() + self.padding_needed_for(self.align());
+ // Warning, removing the checked_add here led to segfaults in #67174. Further
+ // analysis in #69225 seems to indicate that this is an LTO-related
+ // miscompilation, so #67174 might be able to be reapplied in the future.
+ let padded_size = self
+ .size()
+ .checked_add(self.padding_needed_for(self.align()))
+ .ok_or(LayoutErr { private: () })?;
let alloc_size = padded_size.checked_mul(n).ok_or(LayoutErr { private: () })?;
unsafe {
///
/// * the starting address for that memory block was previously
/// returned by a previous call to an allocation method (`alloc`,
-/// `alloc_zeroed`, `alloc_excess`, `alloc_one`, `alloc_array`) or
-/// reallocation method (`realloc`, `realloc_excess`, or
-/// `realloc_array`), and
+/// `alloc_zeroed`, `alloc_excess`) or reallocation method
+/// (`realloc`, `realloc_excess`), and
///
/// * the memory block has not been subsequently deallocated, where
/// blocks are deallocated either by being passed to a deallocation
/// methods in the `AllocRef` trait state that allocation requests
/// must be non-zero size, or else undefined behavior can result.
///
-/// * However, some higher-level allocation methods (`alloc_one`,
-/// `alloc_array`) are well-defined on zero-sized types and can
-/// optionally support them: it is left up to the implementor
-/// whether to return `Err`, or to return `Ok` with some pointer.
-///
/// * If an `AllocRef` implementation chooses to return `Ok` in this
/// case (i.e., the pointer denotes a zero-sized inaccessible block)
/// then that returned pointer must be considered "currently
result
}
+ /// Behaves like `realloc`, but also ensures that the new contents
+ /// are set to zero before being returned.
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe for the same reasons that `realloc` is.
+ ///
+ /// # Errors
+ ///
+ /// Returns `Err` only if the new layout
+ /// does not meet the allocator's size
+ /// and alignment constraints of the allocator, or if reallocation
+ /// otherwise fails.
+ ///
+ /// Implementations are encouraged to return `Err` on memory
+ /// exhaustion rather than panicking or aborting, but this is not
+ /// a strict requirement. (Specifically: it is *legal* to
+ /// implement this trait atop an underlying native allocation
+ /// library that aborts on memory exhaustion.)
+ ///
+ /// Clients wishing to abort computation in response to a
+ /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
+ /// rather than directly invoking `panic!` or similar.
+ ///
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
+ unsafe fn realloc_zeroed(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<NonNull<u8>, AllocErr> {
+ let old_size = layout.size();
+
+ if new_size >= old_size {
+ if let Ok(()) = self.grow_in_place_zeroed(ptr, layout, new_size) {
+ return Ok(ptr);
+ }
+ } else if new_size < old_size {
+ if let Ok(()) = self.shrink_in_place(ptr, layout, new_size) {
+ return Ok(ptr);
+ }
+ }
+
+ // otherwise, fall back on alloc + copy + dealloc.
+ let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+ let result = self.alloc_zeroed(new_layout);
+ if let Ok(new_ptr) = result {
+ ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_ptr(), cmp::min(old_size, new_size));
+ self.dealloc(ptr, layout);
+ }
+ result
+ }
+
/// Behaves like `alloc`, but also ensures that the contents
/// are set to zero before being returned.
///
self.alloc(layout).map(|p| Excess(p, usable_size.1))
}
+ /// Behaves like `alloc`, but also returns the whole size of
+ /// the returned block. For some `layout` inputs, like arrays, this
+ /// may include extra storage usable for additional data.
+ /// Also it ensures that the contents are set to zero before being returned.
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe for the same reasons that `alloc` is.
+ ///
+ /// # Errors
+ ///
+ /// Returning `Err` indicates that either memory is exhausted or
+ /// `layout` does not meet allocator's size or alignment
+ /// constraints, just as in `alloc`.
+ ///
+ /// Clients wishing to abort computation in response to an
+ /// allocation error are encouraged to call the [`handle_alloc_error`] function,
+ /// rather than directly invoking `panic!` or similar.
+ ///
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
+ unsafe fn alloc_excess_zeroed(&mut self, layout: Layout) -> Result<Excess, AllocErr> {
+ let usable_size = self.usable_size(&layout);
+ self.alloc_zeroed(layout).map(|p| Excess(p, usable_size.1))
+ }
+
/// Behaves like `realloc`, but also returns the whole size of
/// the returned block. For some `layout` inputs, like arrays, this
/// may include extra storage usable for additional data.
self.realloc(ptr, layout, new_size).map(|p| Excess(p, usable_size.1))
}
+ /// Behaves like `realloc`, but also returns the whole size of
+ /// the returned block. For some `layout` inputs, like arrays, this
+ /// may include extra storage usable for additional data.
+ /// Also it ensures that the contents are set to zero before being returned.
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe for the same reasons that `realloc` is.
+ ///
+ /// # Errors
+ ///
+ /// Returning `Err` indicates that either memory is exhausted or
+ /// `layout` does not meet allocator's size or alignment
+ /// constraints, just as in `realloc`.
+ ///
+ /// Clients wishing to abort computation in response to a
+ /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
+ /// rather than directly invoking `panic!` or similar.
+ ///
+ /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
+ unsafe fn realloc_excess_zeroed(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<Excess, AllocErr> {
+ let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
+ let usable_size = self.usable_size(&new_layout);
+ self.realloc_zeroed(ptr, layout, new_size).map(|p| Excess(p, usable_size.1))
+ }
+
/// Attempts to extend the allocation referenced by `ptr` to fit `new_size`.
///
/// If this returns `Ok`, then the allocator has asserted that the
if new_size <= u { Ok(()) } else { Err(CannotReallocInPlace) }
}
+ /// Behaves like `grow_in_place`, but also ensures that the new
+ /// contents are set to zero before being returned.
+ ///
+ /// # Safety
+ ///
+ /// This function is unsafe for the same reasons that `grow_in_place` is.
+ ///
+ /// # Errors
+ ///
+ /// Returns `Err(CannotReallocInPlace)` when the allocator is
+ /// unable to assert that the memory block referenced by `ptr`
+ /// could fit `layout`.
+ ///
+ /// Note that one cannot pass `CannotReallocInPlace` to the `handle_alloc_error`
+ /// function; clients are expected either to be able to recover from
+ /// `grow_in_place` failures without aborting, or to fall back on
+ /// another reallocation method before resorting to an abort.
+ unsafe fn grow_in_place_zeroed(
+ &mut self,
+ ptr: NonNull<u8>,
+ layout: Layout,
+ new_size: usize,
+ ) -> Result<(), CannotReallocInPlace> {
+ self.grow_in_place(ptr, layout, new_size)?;
+ ptr.as_ptr().add(layout.size()).write_bytes(0, new_size - layout.size());
+ Ok(())
+ }
+
/// Attempts to shrink the allocation referenced by `ptr` to fit `new_size`.
///
/// If this returns `Ok`, then the allocator has asserted that the
// new_layout.size() <= layout.size() [required by this method]
if l <= new_size { Ok(()) } else { Err(CannotReallocInPlace) }
}
-
- // == COMMON USAGE PATTERNS ==
- // alloc_one, dealloc_one, alloc_array, realloc_array. dealloc_array
-
- /// Allocates a block suitable for holding an instance of `T`.
- ///
- /// Captures a common usage pattern for allocators.
- ///
- /// The returned block is suitable for passing to the
- /// `realloc`/`dealloc` methods of this allocator.
- ///
- /// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
- /// must be considered "currently allocated" and must be
- /// acceptable input to methods such as `realloc` or `dealloc`,
- /// *even if* `T` is a zero-sized type. In other words, if your
- /// `AllocRef` implementation overrides this method in a manner
- /// that can return a zero-sized `ptr`, then all reallocation and
- /// deallocation methods need to be similarly overridden to accept
- /// such values as input.
- ///
- /// # Errors
- ///
- /// Returning `Err` indicates that either memory is exhausted or
- /// `T` does not meet allocator's size or alignment constraints.
- ///
- /// For zero-sized `T`, may return either of `Ok` or `Err`, but
- /// will *not* yield undefined behavior.
- ///
- /// Clients wishing to abort computation in response to an
- /// allocation error are encouraged to call the [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- fn alloc_one<T>(&mut self) -> Result<NonNull<T>, AllocErr>
- where
- Self: Sized,
- {
- let k = Layout::new::<T>();
- if k.size() > 0 { unsafe { self.alloc(k).map(|p| p.cast()) } } else { Err(AllocErr) }
- }
-
- /// Deallocates a block suitable for holding an instance of `T`.
- ///
- /// The given block must have been produced by this allocator,
- /// and must be suitable for storing a `T` (in terms of alignment
- /// as well as minimum and maximum size); otherwise yields
- /// undefined behavior.
- ///
- /// Captures a common usage pattern for allocators.
- ///
- /// # Safety
- ///
- /// This function is unsafe because undefined behavior can result
- /// if the caller does not ensure both:
- ///
- /// * `ptr` must denote a block of memory currently allocated via this allocator
- ///
- /// * the layout of `T` must *fit* that block of memory.
- unsafe fn dealloc_one<T>(&mut self, ptr: NonNull<T>)
- where
- Self: Sized,
- {
- let k = Layout::new::<T>();
- if k.size() > 0 {
- self.dealloc(ptr.cast(), k);
- }
- }
-
- /// Allocates a block suitable for holding `n` instances of `T`.
- ///
- /// Captures a common usage pattern for allocators.
- ///
- /// The returned block is suitable for passing to the
- /// `realloc`/`dealloc` methods of this allocator.
- ///
- /// Note to implementors: If this returns `Ok(ptr)`, then `ptr`
- /// must be considered "currently allocated" and must be
- /// acceptable input to methods such as `realloc` or `dealloc`,
- /// *even if* `T` is a zero-sized type. In other words, if your
- /// `AllocRef` implementation overrides this method in a manner
- /// that can return a zero-sized `ptr`, then all reallocation and
- /// deallocation methods need to be similarly overridden to accept
- /// such values as input.
- ///
- /// # Errors
- ///
- /// Returning `Err` indicates that either memory is exhausted or
- /// `[T; n]` does not meet allocator's size or alignment
- /// constraints.
- ///
- /// For zero-sized `T` or `n == 0`, may return either of `Ok` or
- /// `Err`, but will *not* yield undefined behavior.
- ///
- /// Always returns `Err` on arithmetic overflow.
- ///
- /// Clients wishing to abort computation in response to an
- /// allocation error are encouraged to call the [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- fn alloc_array<T>(&mut self, n: usize) -> Result<NonNull<T>, AllocErr>
- where
- Self: Sized,
- {
- match Layout::array::<T>(n) {
- Ok(layout) if layout.size() > 0 => unsafe { self.alloc(layout).map(|p| p.cast()) },
- _ => Err(AllocErr),
- }
- }
-
- /// Reallocates a block previously suitable for holding `n_old`
- /// instances of `T`, returning a block suitable for holding
- /// `n_new` instances of `T`.
- ///
- /// Captures a common usage pattern for allocators.
- ///
- /// The returned block is suitable for passing to the
- /// `realloc`/`dealloc` methods of this allocator.
- ///
- /// # Safety
- ///
- /// This function is unsafe because undefined behavior can result
- /// if the caller does not ensure all of the following:
- ///
- /// * `ptr` must be currently allocated via this allocator,
- ///
- /// * the layout of `[T; n_old]` must *fit* that block of memory.
- ///
- /// # Errors
- ///
- /// Returning `Err` indicates that either memory is exhausted or
- /// `[T; n_new]` does not meet allocator's size or alignment
- /// constraints.
- ///
- /// For zero-sized `T` or `n_new == 0`, may return either of `Ok` or
- /// `Err`, but will *not* yield undefined behavior.
- ///
- /// Always returns `Err` on arithmetic overflow.
- ///
- /// Clients wishing to abort computation in response to a
- /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
- /// rather than directly invoking `panic!` or similar.
- ///
- /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
- unsafe fn realloc_array<T>(
- &mut self,
- ptr: NonNull<T>,
- n_old: usize,
- n_new: usize,
- ) -> Result<NonNull<T>, AllocErr>
- where
- Self: Sized,
- {
- match (Layout::array::<T>(n_old), Layout::array::<T>(n_new)) {
- (Ok(k_old), Ok(k_new)) if k_old.size() > 0 && k_new.size() > 0 => {
- debug_assert!(k_old.align() == k_new.align());
- self.realloc(ptr.cast(), k_old, k_new.size()).map(NonNull::cast)
- }
- _ => Err(AllocErr),
- }
- }
-
- /// Deallocates a block suitable for holding `n` instances of `T`.
- ///
- /// Captures a common usage pattern for allocators.
- ///
- /// # Safety
- ///
- /// This function is unsafe because undefined behavior can result
- /// if the caller does not ensure both:
- ///
- /// * `ptr` must denote a block of memory currently allocated via this allocator
- ///
- /// * the layout of `[T; n]` must *fit* that block of memory.
- ///
- /// # Errors
- ///
- /// Returning `Err` indicates that either `[T; n]` or the given
- /// memory block does not meet allocator's size or alignment
- /// constraints.
- ///
- /// Always returns `Err` on arithmetic overflow.
- unsafe fn dealloc_array<T>(&mut self, ptr: NonNull<T>, n: usize) -> Result<(), AllocErr>
- where
- Self: Sized,
- {
- match Layout::array::<T>(n) {
- Ok(k) if k.size() > 0 => Ok(self.dealloc(ptr.cast(), k)),
- _ => Err(AllocErr),
- }
- }
}