| use crate::alloc::Layout; | |
| use crate::cmp; | |
| use crate::ptr; | |
| /// A memory allocator that can be registered as the standard library’s default | |
| /// through the `#[global_allocator]` attribute. | |
| /// | |
| /// Some of the methods require that a memory block be *currently | |
| /// allocated* via an allocator. This means that: | |
| /// | |
| /// * the starting address for that memory block was previously | |
| /// returned by a previous call to an allocation method | |
| /// such as `alloc`, and | |
| /// | |
| /// * the memory block has not been subsequently deallocated, where | |
| /// blocks are deallocated either by being passed to a deallocation | |
| /// method such as `dealloc` or by being | |
| /// passed to a reallocation method that returns a non-null pointer. | |
| /// | |
| /// | |
| /// # Example | |
| /// | |
| /// ```no_run | |
| /// use std::alloc::{GlobalAlloc, Layout, alloc}; | |
| /// use std::ptr::null_mut; | |
| /// | |
| /// struct MyAllocator; | |
| /// | |
| /// unsafe impl GlobalAlloc for MyAllocator { | |
| /// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() } | |
| /// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {} | |
| /// } | |
| /// | |
| /// #[global_allocator] | |
| /// static A: MyAllocator = MyAllocator; | |
| /// | |
| /// fn main() { | |
| /// unsafe { | |
| /// assert!(alloc(Layout::new::<u32>()).is_null()) | |
| /// } | |
| /// } | |
| /// ``` | |
| /// | |
| /// # Safety | |
| /// | |
| /// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and | |
| /// implementors must ensure that they adhere to these contracts: | |
| /// | |
| /// * It's undefined behavior if global allocators unwind. This restriction may | |
| /// be lifted in the future, but currently a panic from any of these | |
| /// functions may lead to memory unsafety. | |
| /// | |
| /// * `Layout` queries and calculations in general must be correct. Callers of | |
| /// this trait are allowed to rely on the contracts defined on each method, | |
| /// and implementors must ensure such contracts remain true. | |
| #[stable(feature = "global_alloc", since = "1.28.0")] | |
| pub unsafe trait GlobalAlloc { | |
| /// Allocate memory as described by the given `layout`. | |
| /// | |
| /// Returns a pointer to newly-allocated memory, | |
| /// or null to indicate allocation failure. | |
| /// | |
| /// # Safety | |
| /// | |
| /// This function is unsafe because undefined behavior can result | |
| /// if the caller does not ensure that `layout` has non-zero size. | |
| /// | |
| /// (Extension subtraits might provide more specific bounds on | |
| /// behavior, e.g., guarantee a sentinel address or a null pointer | |
| /// in response to a zero-size allocation request.) | |
| /// | |
| /// The allocated block of memory may or may not be initialized. | |
| /// | |
| /// # Errors | |
| /// | |
| /// Returning a null pointer indicates that either memory is exhausted | |
| /// or `layout` does not meet this allocator's size or alignment constraints. | |
| /// | |
| /// Implementations are encouraged to return null on memory | |
| /// exhaustion rather than 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 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 | |
| #[stable(feature = "global_alloc", since = "1.28.0")] | |
| unsafe fn alloc(&self, layout: Layout) -> *mut u8; | |
| /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`. | |
| /// | |
| /// # Safety | |
| /// | |
| /// This function is unsafe because undefined behavior can result | |
| /// if the caller does not ensure all of the following: | |
| /// | |
| /// * `ptr` must denote a block of memory currently allocated via | |
| /// this allocator, | |
| /// | |
| /// * `layout` must be the same layout that was used | |
| /// to allocate that block of memory, | |
| #[stable(feature = "global_alloc", since = "1.28.0")] | |
| unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout); | |
| /// Behaves like `alloc`, but also ensures that the contents | |
| /// are set to zero before being returned. | |
| /// | |
| /// # Safety | |
| /// | |
| /// This function is unsafe for the same reasons that `alloc` is. | |
| /// However the allocated block of memory is guaranteed to be initialized. | |
| /// | |
| /// # Errors | |
| /// | |
| /// Returning a null pointer 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 | |
| #[stable(feature = "global_alloc", since = "1.28.0")] | |
| unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 { | |
| let size = layout.size(); | |
| // SAFETY: the safety contract for `alloc` must be upheld by the caller. | |
| let ptr = unsafe { self.alloc(layout) }; | |
| if !ptr.is_null() { | |
| // SAFETY: as allocation succeeded, the region from `ptr` | |
| // of size `size` is guaranteed to be valid for writes. | |
| unsafe { ptr::write_bytes(ptr, 0, size) }; | |
| } | |
| ptr | |
| } | |
| /// Shrink or grow a block of memory to the given `new_size`. | |
| /// The block is described by the given `ptr` pointer and `layout`. | |
| /// | |
| /// If this returns a non-null pointer, then ownership of the memory block | |
| /// referenced by `ptr` has been transferred to this allocator. | |
| /// The memory may or may not have been deallocated, | |
| /// and should be considered unusable (unless of course it was | |
| /// transferred back to the caller again via the return value of | |
| /// this method). The new memory block is allocated with `layout`, but | |
| /// with the `size` updated to `new_size`. | |
| /// | |
| /// If this method returns null, then ownership of the memory | |
| /// block has not been transferred to this allocator, and the | |
| /// contents of the memory block are unaltered. | |
| /// | |
| /// # 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, | |
| /// | |
| /// * `layout` must be the same layout that was used | |
| /// to allocate that block of memory, | |
| /// | |
| /// * `new_size` must be greater than zero. | |
| /// | |
| /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, | |
| /// must not overflow (i.e., the rounded value must be less than `usize::MAX`). | |
| /// | |
| /// (Extension subtraits might provide more specific bounds on | |
| /// behavior, e.g., guarantee a sentinel address or a null pointer | |
| /// in response to a zero-size allocation request.) | |
| /// | |
| /// # Errors | |
| /// | |
| /// Returns null if the new layout does not meet the size | |
| /// and alignment constraints of the allocator, or if reallocation | |
| /// otherwise fails. | |
| /// | |
| /// Implementations are encouraged to return null 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 | |
| #[stable(feature = "global_alloc", since = "1.28.0")] | |
| unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 { | |
| // SAFETY: the caller must ensure that the `new_size` does not overflow. | |
| // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid. | |
| let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; | |
| // SAFETY: the caller must ensure that `new_layout` is greater than zero. | |
| let new_ptr = unsafe { self.alloc(new_layout) }; | |
| if !new_ptr.is_null() { | |
| // SAFETY: the previously allocated block cannot overlap the newly allocated block. | |
| // The safety contract for `dealloc` must be upheld by the caller. | |
| unsafe { | |
| ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size)); | |
| self.dealloc(ptr, layout); | |
| } | |
| } | |
| new_ptr | |
| } | |
| } |