Trait GlobalAlloc
unsafe trait GlobalAlloc
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
deallocor by being passed to a reallocation method that returns a non-null pointer.
Example
use ;
use UnsafeCell;
use null_mut;
use ;
const ARENA_SIZE: usize = 128 * 1024;
const MAX_SUPPORTED_ALIGN: usize = 4096;
// 4096 == MAX_SUPPORTED_ALIGN
static ALLOCATOR: SimpleAllocator = SimpleAllocator ;
unsafe
unsafe
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.
-
Layoutqueries 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. -
You must not rely on allocations actually happening, even if there are explicit heap allocations in the source. The optimizer may detect unused allocations that it can either eliminate entirely or move to the stack and thus never invoke the allocator. The optimizer may further assume that allocation is infallible, so code that used to fail due to allocator failures may now suddenly work because the optimizer worked around the need for an allocation. More concretely, the following code example is unsound, irrespective of whether your custom allocator allows counting how many allocations have happened.
drop; let number_of_heap_allocs = /* call private allocator API */; unsafeNote that the optimizations mentioned above are not the only optimization that can be applied. You may generally not rely on heap allocations happening if they can be removed without changing program behavior. Whether allocations happen or not is not part of the program behavior, even if it could be detected via an allocator that tracks allocations by printing or otherwise having side effects.
Re-entrance
When implementing a global allocator, one has to be careful not to create an infinitely recursive
implementation by accident, as many constructs in the Rust standard library may allocate in
their implementation. For example, on some platforms, std::sync::Mutex may allocate, so using
it is highly problematic in a global allocator.
For this reason, one should generally stick to library features available through
core, and avoid using std in a global allocator. A few features from std are
guaranteed to not use #[global_allocator] to allocate:
std::thread_local,std::thread::current,std::thread::parkandstd::thread::Thread'sunparkmethod andCloneimplementation.
Required Methods
unsafe fn alloc(self: &Self, layout: Layout) -> *mut u8Allocates memory as described by the given
layout.Returns a pointer to newly-allocated memory, or null to indicate allocation failure.
Safety
layoutmust have non-zero size. Attempting to allocate for a zero-sizedlayoutwill result in undefined behavior.(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
layoutdoes 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_errorfunction, rather than directly invokingpanic!or similar.unsafe fn dealloc(self: &Self, ptr: *mut u8, layout: Layout)Deallocates the block of memory at the given
ptrpointer with the givenlayout.Safety
The caller must ensure:
-
ptris a block of memory currently allocated via this allocator and, -
layoutis the same layout that was used to allocate that block of memory.
Otherwise the behavior is undefined.
-
Provided Methods
unsafe fn alloc_zeroed(self: &Self, layout: Layout) -> *mut u8Behaves like
alloc, but also ensures that the contents are set to zero before being returned.Safety
The caller has to ensure that
layouthas non-zero size. Likealloczero sizedlayoutwill result in undefined behavior. However the allocated block of memory is guaranteed to be initialized.Errors
Returning a null pointer indicates that either memory is exhausted or
layoutdoes not meet allocator's size or alignment constraints, just as inalloc.Clients wishing to abort computation in response to an allocation error are encouraged to call the
handle_alloc_errorfunction, rather than directly invokingpanic!or similar.unsafe fn realloc(self: &Self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8Shrinks or grows a block of memory to the given
new_sizein bytes. The block is described by the givenptrpointer andlayout.If this returns a non-null pointer, then ownership of the memory block referenced by
ptrhas been transferred to this allocator. Any access to the oldptris Undefined Behavior, even if the allocation remained in-place. The newly returned pointer is the only valid pointer for accessing this memory now.The new memory block is allocated with
layout, but with thesizeupdated tonew_sizein bytes. This new layout must be used when deallocating the new memory block withdealloc. The range0..min(layout.size(), new_size)of the new memory block is guaranteed to have the same values as the original block.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
The caller must ensure that:
-
ptris allocated via this allocator, -
layoutis the same layout that was used to allocate that block of memory, -
new_sizeis greater than zero. -
new_size, when rounded up to the nearest multiple oflayout.align(), does not overflowisize(i.e., the rounded value must be less than or equal toisize::MAX).
If these are not followed, the behavior is undefined.
(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_errorfunction, rather than directly invokingpanic!or similar.-