]> git.proxmox.com Git - rustc.git/blame - library/core/src/alloc/global.rs
New upstream version 1.54.0+dfsg1
[rustc.git] / library / core / src / alloc / global.rs
CommitLineData
ba9703b0
XL
1use crate::alloc::Layout;
2use crate::cmp;
3use crate::ptr;
4
5/// A memory allocator that can be registered as the standard library’s default
6/// through the `#[global_allocator]` attribute.
7///
8/// Some of the methods require that a memory block be *currently
9/// allocated* via an allocator. This means that:
10///
11/// * the starting address for that memory block was previously
12/// returned by a previous call to an allocation method
13/// such as `alloc`, and
14///
15/// * the memory block has not been subsequently deallocated, where
16/// blocks are deallocated either by being passed to a deallocation
17/// method such as `dealloc` or by being
18/// passed to a reallocation method that returns a non-null pointer.
19///
20///
21/// # Example
22///
23/// ```no_run
24/// use std::alloc::{GlobalAlloc, Layout, alloc};
25/// use std::ptr::null_mut;
26///
27/// struct MyAllocator;
28///
29/// unsafe impl GlobalAlloc for MyAllocator {
30/// unsafe fn alloc(&self, _layout: Layout) -> *mut u8 { null_mut() }
31/// unsafe fn dealloc(&self, _ptr: *mut u8, _layout: Layout) {}
32/// }
33///
34/// #[global_allocator]
35/// static A: MyAllocator = MyAllocator;
36///
37/// fn main() {
38/// unsafe {
39/// assert!(alloc(Layout::new::<u32>()).is_null())
40/// }
41/// }
42/// ```
43///
44/// # Safety
45///
46/// The `GlobalAlloc` trait is an `unsafe` trait for a number of reasons, and
47/// implementors must ensure that they adhere to these contracts:
48///
49/// * It's undefined behavior if global allocators unwind. This restriction may
50/// be lifted in the future, but currently a panic from any of these
51/// functions may lead to memory unsafety.
52///
53/// * `Layout` queries and calculations in general must be correct. Callers of
54/// this trait are allowed to rely on the contracts defined on each method,
55/// and implementors must ensure such contracts remain true.
5869c6ff
XL
56///
57/// * You may not rely on allocations actually happening, even if there are explicit
58/// heap allocations in the source. The optimizer may detect unused allocations that it can either
59/// eliminate entirely or move to the stack and thus never invoke the allocator. The
60/// optimizer may further assume that allocation is infallible, so code that used to fail due
61/// to allocator failures may now suddenly work because the optimizer worked around the
62/// need for an allocation. More concretely, the following code example is unsound, irrespective
63/// of whether your custom allocator allows counting how many allocations have happened.
64///
65/// ```rust,ignore (unsound and has placeholders)
66/// drop(Box::new(42));
67/// let number_of_heap_allocs = /* call private allocator API */;
68/// unsafe { std::intrinsics::assume(number_of_heap_allocs > 0); }
69/// ```
70///
71/// Note that the optimizations mentioned above are not the only
72/// optimization that can be applied. You may generally not rely on heap allocations
73/// happening if they can be removed without changing program behavior.
74/// Whether allocations happen or not is not part of the program behavior, even if it
75/// could be detected via an allocator that tracks allocations by printing or otherwise
76/// having side effects.
ba9703b0
XL
77#[stable(feature = "global_alloc", since = "1.28.0")]
78pub unsafe trait GlobalAlloc {
79 /// Allocate memory as described by the given `layout`.
80 ///
81 /// Returns a pointer to newly-allocated memory,
82 /// or null to indicate allocation failure.
83 ///
84 /// # Safety
85 ///
86 /// This function is unsafe because undefined behavior can result
87 /// if the caller does not ensure that `layout` has non-zero size.
88 ///
89 /// (Extension subtraits might provide more specific bounds on
90 /// behavior, e.g., guarantee a sentinel address or a null pointer
91 /// in response to a zero-size allocation request.)
92 ///
93 /// The allocated block of memory may or may not be initialized.
94 ///
95 /// # Errors
96 ///
97 /// Returning a null pointer indicates that either memory is exhausted
98 /// or `layout` does not meet this allocator's size or alignment constraints.
99 ///
100 /// Implementations are encouraged to return null on memory
101 /// exhaustion rather than aborting, but this is not
102 /// a strict requirement. (Specifically: it is *legal* to
103 /// implement this trait atop an underlying native allocation
104 /// library that aborts on memory exhaustion.)
105 ///
106 /// Clients wishing to abort computation in response to an
107 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
108 /// rather than directly invoking `panic!` or similar.
109 ///
110 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
111 #[stable(feature = "global_alloc", since = "1.28.0")]
112 unsafe fn alloc(&self, layout: Layout) -> *mut u8;
113
114 /// Deallocate the block of memory at the given `ptr` pointer with the given `layout`.
115 ///
116 /// # Safety
117 ///
118 /// This function is unsafe because undefined behavior can result
119 /// if the caller does not ensure all of the following:
120 ///
121 /// * `ptr` must denote a block of memory currently allocated via
122 /// this allocator,
123 ///
124 /// * `layout` must be the same layout that was used
6a06907d 125 /// to allocate that block of memory.
ba9703b0
XL
126 #[stable(feature = "global_alloc", since = "1.28.0")]
127 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout);
128
129 /// Behaves like `alloc`, but also ensures that the contents
130 /// are set to zero before being returned.
131 ///
132 /// # Safety
133 ///
134 /// This function is unsafe for the same reasons that `alloc` is.
135 /// However the allocated block of memory is guaranteed to be initialized.
136 ///
137 /// # Errors
138 ///
139 /// Returning a null pointer indicates that either memory is exhausted
140 /// or `layout` does not meet allocator's size or alignment constraints,
141 /// just as in `alloc`.
142 ///
143 /// Clients wishing to abort computation in response to an
144 /// allocation error are encouraged to call the [`handle_alloc_error`] function,
145 /// rather than directly invoking `panic!` or similar.
146 ///
147 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
148 #[stable(feature = "global_alloc", since = "1.28.0")]
149 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
150 let size = layout.size();
f035d41b
XL
151 // SAFETY: the safety contract for `alloc` must be upheld by the caller.
152 let ptr = unsafe { self.alloc(layout) };
ba9703b0 153 if !ptr.is_null() {
f035d41b
XL
154 // SAFETY: as allocation succeeded, the region from `ptr`
155 // of size `size` is guaranteed to be valid for writes.
156 unsafe { ptr::write_bytes(ptr, 0, size) };
ba9703b0
XL
157 }
158 ptr
159 }
160
161 /// Shrink or grow a block of memory to the given `new_size`.
162 /// The block is described by the given `ptr` pointer and `layout`.
163 ///
164 /// If this returns a non-null pointer, then ownership of the memory block
165 /// referenced by `ptr` has been transferred to this allocator.
166 /// The memory may or may not have been deallocated,
167 /// and should be considered unusable (unless of course it was
168 /// transferred back to the caller again via the return value of
169 /// this method). The new memory block is allocated with `layout`, but
6a06907d
XL
170 /// with the `size` updated to `new_size`. This new layout should be
171 /// used when deallocating the new memory block with `dealloc`. The range
172 /// `0..min(layout.size(), new_size)` of the new memory block is
173 /// guaranteed to have the same values as the original block.
ba9703b0
XL
174 ///
175 /// If this method returns null, then ownership of the memory
176 /// block has not been transferred to this allocator, and the
177 /// contents of the memory block are unaltered.
178 ///
179 /// # Safety
180 ///
181 /// This function is unsafe because undefined behavior can result
182 /// if the caller does not ensure all of the following:
183 ///
184 /// * `ptr` must be currently allocated via this allocator,
185 ///
186 /// * `layout` must be the same layout that was used
187 /// to allocate that block of memory,
188 ///
189 /// * `new_size` must be greater than zero.
190 ///
191 /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`,
192 /// must not overflow (i.e., the rounded value must be less than `usize::MAX`).
193 ///
194 /// (Extension subtraits might provide more specific bounds on
195 /// behavior, e.g., guarantee a sentinel address or a null pointer
196 /// in response to a zero-size allocation request.)
197 ///
198 /// # Errors
199 ///
200 /// Returns null if the new layout does not meet the size
201 /// and alignment constraints of the allocator, or if reallocation
202 /// otherwise fails.
203 ///
204 /// Implementations are encouraged to return null on memory
205 /// exhaustion rather than panicking or aborting, but this is not
206 /// a strict requirement. (Specifically: it is *legal* to
207 /// implement this trait atop an underlying native allocation
208 /// library that aborts on memory exhaustion.)
209 ///
210 /// Clients wishing to abort computation in response to a
211 /// reallocation error are encouraged to call the [`handle_alloc_error`] function,
212 /// rather than directly invoking `panic!` or similar.
213 ///
214 /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html
215 #[stable(feature = "global_alloc", since = "1.28.0")]
216 unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
f035d41b
XL
217 // SAFETY: the caller must ensure that the `new_size` does not overflow.
218 // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid.
219 let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) };
220 // SAFETY: the caller must ensure that `new_layout` is greater than zero.
221 let new_ptr = unsafe { self.alloc(new_layout) };
ba9703b0 222 if !new_ptr.is_null() {
f035d41b
XL
223 // SAFETY: the previously allocated block cannot overlap the newly allocated block.
224 // The safety contract for `dealloc` must be upheld by the caller.
225 unsafe {
226 ptr::copy_nonoverlapping(ptr, new_ptr, cmp::min(layout.size(), new_size));
227 self.dealloc(ptr, layout);
228 }
ba9703b0
XL
229 }
230 new_ptr
231 }
232}