diff options
| author | bors <bors@rust-lang.org> | 2020-02-12 10:10:15 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2020-02-12 10:10:15 +0000 |
| commit | cd5441faf4e56d136d7c05d5eb55b4a41396edaf (patch) | |
| tree | 27e27611e789f2cf88d5efe83c1fa543dee6590f /src/libcore | |
| parent | 7cba853b4f6080bf7831169fe5632ec9b6833242 (diff) | |
| parent | 486856f75fd8c681f728ed3445e285666dbe19b9 (diff) | |
| download | rust-cd5441faf4e56d136d7c05d5eb55b4a41396edaf.tar.gz rust-cd5441faf4e56d136d7c05d5eb55b4a41396edaf.zip | |
Auto merge of #69088 - JohnTitor:rollup-x7bk7h7, r=JohnTitor
Rollup of 11 pull requests Successful merges: - #67695 (Added dyn and true keyword docs) - #68487 ([experiment] Support linking from a .rlink file) - #68554 (Split lang_items to crates `rustc_hir` and `rustc_passes`.) - #68937 (Test failure of unchecked arithmetic intrinsics in const eval) - #68947 (Python script PEP8 style guide space formatting and minor Python source cleanup) - #68999 (remove dependency on itertools) - #69026 (Remove common usage pattern from `AllocRef`) - #69027 (Add missing `_zeroed` varants to `AllocRef`) - #69058 (Preparation for allocator aware `Box`) - #69070 (Add self to .mailmap) - #69077 (Fix outdated doc comment.) Failed merges: r? @ghost
Diffstat (limited to 'src/libcore')
| -rw-r--r-- | src/libcore/alloc.rs | 338 |
1 files changed, 139 insertions, 199 deletions
diff --git a/src/libcore/alloc.rs b/src/libcore/alloc.rs index 38df843d258..71f7f971eab 100644 --- a/src/libcore/alloc.rs +++ b/src/libcore/alloc.rs @@ -593,9 +593,8 @@ pub unsafe trait GlobalAlloc { /// /// * 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 @@ -606,11 +605,6 @@ pub unsafe trait GlobalAlloc { /// 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 @@ -853,6 +847,59 @@ pub unsafe trait AllocRef { 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. /// @@ -904,6 +951,31 @@ pub unsafe trait AllocRef { 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. @@ -934,6 +1006,37 @@ pub unsafe trait AllocRef { 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 @@ -983,6 +1086,34 @@ pub unsafe trait AllocRef { 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 @@ -1035,195 +1166,4 @@ pub unsafe trait AllocRef { // 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), - } - } } |
