]> git.proxmox.com Git - rustc.git/blob - src/liballoc/alloc.rs
New upstream version 1.44.1+dfsg1
[rustc.git] / src / liballoc / alloc.rs
1 //! Memory allocation APIs
2
3 #![stable(feature = "alloc_module", since = "1.28.0")]
4
5 use core::intrinsics::{self, min_align_of_val, size_of_val};
6 use core::ptr::{NonNull, Unique};
7
8 #[stable(feature = "alloc_module", since = "1.28.0")]
9 #[doc(inline)]
10 pub use core::alloc::*;
11
12 #[cfg(test)]
13 mod tests;
14
15 extern "Rust" {
16 // These are the magic symbols to call the global allocator. rustc generates
17 // them from the `#[global_allocator]` attribute if there is one, or uses the
18 // default implementations in libstd (`__rdl_alloc` etc in `src/libstd/alloc.rs`)
19 // otherwise.
20 #[rustc_allocator]
21 #[rustc_allocator_nounwind]
22 fn __rust_alloc(size: usize, align: usize) -> *mut u8;
23 #[rustc_allocator_nounwind]
24 fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
25 #[rustc_allocator_nounwind]
26 fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
27 #[rustc_allocator_nounwind]
28 fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
29 }
30
31 /// The global memory allocator.
32 ///
33 /// This type implements the [`AllocRef`] trait by forwarding calls
34 /// to the allocator registered with the `#[global_allocator]` attribute
35 /// if there is one, or the `std` crate’s default.
36 ///
37 /// Note: while this type is unstable, the functionality it provides can be
38 /// accessed through the [free functions in `alloc`](index.html#functions).
39 ///
40 /// [`AllocRef`]: trait.AllocRef.html
41 #[unstable(feature = "allocator_api", issue = "32838")]
42 #[derive(Copy, Clone, Default, Debug)]
43 pub struct Global;
44
45 /// Allocate memory with the global allocator.
46 ///
47 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
48 /// of the allocator registered with the `#[global_allocator]` attribute
49 /// if there is one, or the `std` crate’s default.
50 ///
51 /// This function is expected to be deprecated in favor of the `alloc` method
52 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
53 ///
54 /// # Safety
55 ///
56 /// See [`GlobalAlloc::alloc`].
57 ///
58 /// [`Global`]: struct.Global.html
59 /// [`AllocRef`]: trait.AllocRef.html
60 /// [`GlobalAlloc::alloc`]: trait.GlobalAlloc.html#tymethod.alloc
61 ///
62 /// # Examples
63 ///
64 /// ```
65 /// use std::alloc::{alloc, dealloc, Layout};
66 ///
67 /// unsafe {
68 /// let layout = Layout::new::<u16>();
69 /// let ptr = alloc(layout);
70 ///
71 /// *(ptr as *mut u16) = 42;
72 /// assert_eq!(*(ptr as *mut u16), 42);
73 ///
74 /// dealloc(ptr, layout);
75 /// }
76 /// ```
77 #[stable(feature = "global_alloc", since = "1.28.0")]
78 #[inline]
79 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
80 __rust_alloc(layout.size(), layout.align())
81 }
82
83 /// Deallocate memory with the global allocator.
84 ///
85 /// This function forwards calls to the [`GlobalAlloc::dealloc`] method
86 /// of the allocator registered with the `#[global_allocator]` attribute
87 /// if there is one, or the `std` crate’s default.
88 ///
89 /// This function is expected to be deprecated in favor of the `dealloc` method
90 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
91 ///
92 /// # Safety
93 ///
94 /// See [`GlobalAlloc::dealloc`].
95 ///
96 /// [`Global`]: struct.Global.html
97 /// [`AllocRef`]: trait.AllocRef.html
98 /// [`GlobalAlloc::dealloc`]: trait.GlobalAlloc.html#tymethod.dealloc
99 #[stable(feature = "global_alloc", since = "1.28.0")]
100 #[inline]
101 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
102 __rust_dealloc(ptr, layout.size(), layout.align())
103 }
104
105 /// Reallocate memory with the global allocator.
106 ///
107 /// This function forwards calls to the [`GlobalAlloc::realloc`] method
108 /// of the allocator registered with the `#[global_allocator]` attribute
109 /// if there is one, or the `std` crate’s default.
110 ///
111 /// This function is expected to be deprecated in favor of the `realloc` method
112 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
113 ///
114 /// # Safety
115 ///
116 /// See [`GlobalAlloc::realloc`].
117 ///
118 /// [`Global`]: struct.Global.html
119 /// [`AllocRef`]: trait.AllocRef.html
120 /// [`GlobalAlloc::realloc`]: trait.GlobalAlloc.html#method.realloc
121 #[stable(feature = "global_alloc", since = "1.28.0")]
122 #[inline]
123 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
124 __rust_realloc(ptr, layout.size(), layout.align(), new_size)
125 }
126
127 /// Allocate zero-initialized memory with the global allocator.
128 ///
129 /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
130 /// of the allocator registered with the `#[global_allocator]` attribute
131 /// if there is one, or the `std` crate’s default.
132 ///
133 /// This function is expected to be deprecated in favor of the `alloc_zeroed` method
134 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
135 ///
136 /// # Safety
137 ///
138 /// See [`GlobalAlloc::alloc_zeroed`].
139 ///
140 /// [`Global`]: struct.Global.html
141 /// [`AllocRef`]: trait.AllocRef.html
142 /// [`GlobalAlloc::alloc_zeroed`]: trait.GlobalAlloc.html#method.alloc_zeroed
143 ///
144 /// # Examples
145 ///
146 /// ```
147 /// use std::alloc::{alloc_zeroed, dealloc, Layout};
148 ///
149 /// unsafe {
150 /// let layout = Layout::new::<u16>();
151 /// let ptr = alloc_zeroed(layout);
152 ///
153 /// assert_eq!(*(ptr as *mut u16), 0);
154 ///
155 /// dealloc(ptr, layout);
156 /// }
157 /// ```
158 #[stable(feature = "global_alloc", since = "1.28.0")]
159 #[inline]
160 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
161 __rust_alloc_zeroed(layout.size(), layout.align())
162 }
163
164 #[unstable(feature = "allocator_api", issue = "32838")]
165 unsafe impl AllocRef for Global {
166 #[inline]
167 fn alloc(&mut self, layout: Layout, init: AllocInit) -> Result<MemoryBlock, AllocErr> {
168 unsafe {
169 let size = layout.size();
170 if size == 0 {
171 Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
172 } else {
173 let raw_ptr = match init {
174 AllocInit::Uninitialized => alloc(layout),
175 AllocInit::Zeroed => alloc_zeroed(layout),
176 };
177 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
178 Ok(MemoryBlock { ptr, size })
179 }
180 }
181 }
182
183 #[inline]
184 unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
185 if layout.size() != 0 {
186 dealloc(ptr.as_ptr(), layout)
187 }
188 }
189
190 #[inline]
191 unsafe fn grow(
192 &mut self,
193 ptr: NonNull<u8>,
194 layout: Layout,
195 new_size: usize,
196 placement: ReallocPlacement,
197 init: AllocInit,
198 ) -> Result<MemoryBlock, AllocErr> {
199 let size = layout.size();
200 debug_assert!(
201 new_size >= size,
202 "`new_size` must be greater than or equal to `memory.size()`"
203 );
204
205 if size == new_size {
206 return Ok(MemoryBlock { ptr, size });
207 }
208
209 match placement {
210 ReallocPlacement::InPlace => Err(AllocErr),
211 ReallocPlacement::MayMove if layout.size() == 0 => {
212 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
213 self.alloc(new_layout, init)
214 }
215 ReallocPlacement::MayMove => {
216 // `realloc` probably checks for `new_size > size` or something similar.
217 intrinsics::assume(new_size > size);
218 let ptr = realloc(ptr.as_ptr(), layout, new_size);
219 let memory =
220 MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size };
221 init.init_offset(memory, size);
222 Ok(memory)
223 }
224 }
225 }
226
227 #[inline]
228 unsafe fn shrink(
229 &mut self,
230 ptr: NonNull<u8>,
231 layout: Layout,
232 new_size: usize,
233 placement: ReallocPlacement,
234 ) -> Result<MemoryBlock, AllocErr> {
235 let size = layout.size();
236 debug_assert!(
237 new_size <= size,
238 "`new_size` must be smaller than or equal to `memory.size()`"
239 );
240
241 if size == new_size {
242 return Ok(MemoryBlock { ptr, size });
243 }
244
245 match placement {
246 ReallocPlacement::InPlace => Err(AllocErr),
247 ReallocPlacement::MayMove if new_size == 0 => {
248 self.dealloc(ptr, layout);
249 Ok(MemoryBlock { ptr: layout.dangling(), size: 0 })
250 }
251 ReallocPlacement::MayMove => {
252 // `realloc` probably checks for `new_size < size` or something similar.
253 intrinsics::assume(new_size < size);
254 let ptr = realloc(ptr.as_ptr(), layout, new_size);
255 Ok(MemoryBlock { ptr: NonNull::new(ptr).ok_or(AllocErr)?, size: new_size })
256 }
257 }
258 }
259 }
260
261 /// The allocator for unique pointers.
262 // This function must not unwind. If it does, MIR codegen will fail.
263 #[cfg(not(test))]
264 #[lang = "exchange_malloc"]
265 #[inline]
266 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
267 let layout = Layout::from_size_align_unchecked(size, align);
268 match Global.alloc(layout, AllocInit::Uninitialized) {
269 Ok(memory) => memory.ptr.as_ptr(),
270 Err(_) => handle_alloc_error(layout),
271 }
272 }
273
274 #[cfg_attr(not(test), lang = "box_free")]
275 #[inline]
276 // This signature has to be the same as `Box`, otherwise an ICE will happen.
277 // When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as
278 // well.
279 // For example if `Box` is changed to `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
280 // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
281 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
282 let size = size_of_val(ptr.as_ref());
283 let align = min_align_of_val(ptr.as_ref());
284 let layout = Layout::from_size_align_unchecked(size, align);
285 Global.dealloc(ptr.cast().into(), layout)
286 }
287
288 /// Abort on memory allocation error or failure.
289 ///
290 /// Callers of memory allocation APIs wishing to abort computation
291 /// in response to an allocation error are encouraged to call this function,
292 /// rather than directly invoking `panic!` or similar.
293 ///
294 /// The default behavior of this function is to print a message to standard error
295 /// and abort the process.
296 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
297 ///
298 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
299 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
300 #[stable(feature = "global_alloc", since = "1.28.0")]
301 #[rustc_allocator_nounwind]
302 pub fn handle_alloc_error(layout: Layout) -> ! {
303 extern "Rust" {
304 #[lang = "oom"]
305 fn oom_impl(layout: Layout) -> !;
306 }
307 unsafe { oom_impl(layout) }
308 }