]> git.lizzy.rs Git - rust.git/blob - library/alloc/src/alloc.rs
Auto merge of #77502 - varkor:const-generics-suggest-enclosing-braces, r=petrochenkov
[rust.git] / library / alloc / src / alloc.rs
1 //! Memory allocation APIs
2
3 #![stable(feature = "alloc_module", since = "1.28.0")]
4
5 #[cfg(not(test))]
6 use core::intrinsics;
7 use core::intrinsics::{min_align_of_val, size_of_val};
8
9 use core::ptr::Unique;
10 #[cfg(not(test))]
11 use core::ptr::{self, NonNull};
12
13 #[stable(feature = "alloc_module", since = "1.28.0")]
14 #[doc(inline)]
15 pub use core::alloc::*;
16
17 #[cfg(test)]
18 mod tests;
19
20 extern "Rust" {
21     // These are the magic symbols to call the global allocator.  rustc generates
22     // them to call `__rg_alloc` etc. if there is a `#[global_allocator]` attribute
23     // (the code expanding that attribute macro generates those functions), or to call
24     // the default implementations in libstd (`__rdl_alloc` etc. in `library/std/src/alloc.rs`)
25     // otherwise.
26     #[rustc_allocator]
27     #[rustc_allocator_nounwind]
28     fn __rust_alloc(size: usize, align: usize) -> *mut u8;
29     #[rustc_allocator_nounwind]
30     fn __rust_dealloc(ptr: *mut u8, size: usize, align: usize);
31     #[rustc_allocator_nounwind]
32     fn __rust_realloc(ptr: *mut u8, old_size: usize, align: usize, new_size: usize) -> *mut u8;
33     #[rustc_allocator_nounwind]
34     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
35 }
36
37 /// The global memory allocator.
38 ///
39 /// This type implements the [`AllocRef`] trait by forwarding calls
40 /// to the allocator registered with the `#[global_allocator]` attribute
41 /// if there is one, or the `std` crate’s default.
42 ///
43 /// Note: while this type is unstable, the functionality it provides can be
44 /// accessed through the [free functions in `alloc`](self#functions).
45 #[unstable(feature = "allocator_api", issue = "32838")]
46 #[derive(Copy, Clone, Default, Debug)]
47 #[cfg(not(test))]
48 pub struct Global;
49
50 #[cfg(test)]
51 pub use std::alloc::Global;
52
53 /// Allocate memory with the global allocator.
54 ///
55 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
56 /// of the allocator registered with the `#[global_allocator]` attribute
57 /// if there is one, or the `std` crate’s default.
58 ///
59 /// This function is expected to be deprecated in favor of the `alloc` method
60 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
61 ///
62 /// # Safety
63 ///
64 /// See [`GlobalAlloc::alloc`].
65 ///
66 /// # Examples
67 ///
68 /// ```
69 /// use std::alloc::{alloc, dealloc, Layout};
70 ///
71 /// unsafe {
72 ///     let layout = Layout::new::<u16>();
73 ///     let ptr = alloc(layout);
74 ///
75 ///     *(ptr as *mut u16) = 42;
76 ///     assert_eq!(*(ptr as *mut u16), 42);
77 ///
78 ///     dealloc(ptr, layout);
79 /// }
80 /// ```
81 #[stable(feature = "global_alloc", since = "1.28.0")]
82 #[inline]
83 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
84     unsafe { __rust_alloc(layout.size(), layout.align()) }
85 }
86
87 /// Deallocate memory with the global allocator.
88 ///
89 /// This function forwards calls to the [`GlobalAlloc::dealloc`] method
90 /// of the allocator registered with the `#[global_allocator]` attribute
91 /// if there is one, or the `std` crate’s default.
92 ///
93 /// This function is expected to be deprecated in favor of the `dealloc` method
94 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
95 ///
96 /// # Safety
97 ///
98 /// See [`GlobalAlloc::dealloc`].
99 #[stable(feature = "global_alloc", since = "1.28.0")]
100 #[inline]
101 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
102     unsafe { __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 #[stable(feature = "global_alloc", since = "1.28.0")]
118 #[inline]
119 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
120     unsafe { __rust_realloc(ptr, layout.size(), layout.align(), new_size) }
121 }
122
123 /// Allocate zero-initialized memory with the global allocator.
124 ///
125 /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
126 /// of the allocator registered with the `#[global_allocator]` attribute
127 /// if there is one, or the `std` crate’s default.
128 ///
129 /// This function is expected to be deprecated in favor of the `alloc_zeroed` method
130 /// of the [`Global`] type when it and the [`AllocRef`] trait become stable.
131 ///
132 /// # Safety
133 ///
134 /// See [`GlobalAlloc::alloc_zeroed`].
135 ///
136 /// # Examples
137 ///
138 /// ```
139 /// use std::alloc::{alloc_zeroed, dealloc, Layout};
140 ///
141 /// unsafe {
142 ///     let layout = Layout::new::<u16>();
143 ///     let ptr = alloc_zeroed(layout);
144 ///
145 ///     assert_eq!(*(ptr as *mut u16), 0);
146 ///
147 ///     dealloc(ptr, layout);
148 /// }
149 /// ```
150 #[stable(feature = "global_alloc", since = "1.28.0")]
151 #[inline]
152 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
153     unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
154 }
155
156 #[cfg(not(test))]
157 impl Global {
158     #[inline]
159     fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocError> {
160         match layout.size() {
161             0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
162             // SAFETY: `layout` is non-zero in size,
163             size => unsafe {
164                 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
165                 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
166                 Ok(NonNull::slice_from_raw_parts(ptr, size))
167             },
168         }
169     }
170
171     // SAFETY: Same as `AllocRef::grow`
172     #[inline]
173     unsafe fn grow_impl(
174         &self,
175         ptr: NonNull<u8>,
176         old_layout: Layout,
177         new_layout: Layout,
178         zeroed: bool,
179     ) -> Result<NonNull<[u8]>, AllocError> {
180         debug_assert!(
181             new_layout.size() >= old_layout.size(),
182             "`new_layout.size()` must be greater than or equal to `old_layout.size()`"
183         );
184
185         match old_layout.size() {
186             0 => self.alloc_impl(new_layout, zeroed),
187
188             // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
189             // as required by safety conditions. Other conditions must be upheld by the caller
190             old_size if old_layout.align() == new_layout.align() => unsafe {
191                 let new_size = new_layout.size();
192
193                 // `realloc` probably checks for `new_size >= old_layout.size()` or something similar.
194                 intrinsics::assume(new_size >= old_layout.size());
195
196                 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
197                 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
198                 if zeroed {
199                     raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
200                 }
201                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
202             },
203
204             // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`,
205             // both the old and new memory allocation are valid for reads and writes for `old_size`
206             // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
207             // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
208             // for `dealloc` must be upheld by the caller.
209             old_size => unsafe {
210                 let new_ptr = self.alloc_impl(new_layout, zeroed)?;
211                 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size);
212                 self.dealloc(ptr, old_layout);
213                 Ok(new_ptr)
214             },
215         }
216     }
217 }
218
219 #[unstable(feature = "allocator_api", issue = "32838")]
220 #[cfg(not(test))]
221 unsafe impl AllocRef for Global {
222     #[inline]
223     fn alloc(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
224         self.alloc_impl(layout, false)
225     }
226
227     #[inline]
228     fn alloc_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError> {
229         self.alloc_impl(layout, true)
230     }
231
232     #[inline]
233     unsafe fn dealloc(&self, ptr: NonNull<u8>, layout: Layout) {
234         if layout.size() != 0 {
235             // SAFETY: `layout` is non-zero in size,
236             // other conditions must be upheld by the caller
237             unsafe { dealloc(ptr.as_ptr(), layout) }
238         }
239     }
240
241     #[inline]
242     unsafe fn grow(
243         &self,
244         ptr: NonNull<u8>,
245         old_layout: Layout,
246         new_layout: Layout,
247     ) -> Result<NonNull<[u8]>, AllocError> {
248         // SAFETY: all conditions must be upheld by the caller
249         unsafe { self.grow_impl(ptr, old_layout, new_layout, false) }
250     }
251
252     #[inline]
253     unsafe fn grow_zeroed(
254         &self,
255         ptr: NonNull<u8>,
256         old_layout: Layout,
257         new_layout: Layout,
258     ) -> Result<NonNull<[u8]>, AllocError> {
259         // SAFETY: all conditions must be upheld by the caller
260         unsafe { self.grow_impl(ptr, old_layout, new_layout, true) }
261     }
262
263     #[inline]
264     unsafe fn shrink(
265         &self,
266         ptr: NonNull<u8>,
267         old_layout: Layout,
268         new_layout: Layout,
269     ) -> Result<NonNull<[u8]>, AllocError> {
270         debug_assert!(
271             new_layout.size() <= old_layout.size(),
272             "`new_layout.size()` must be smaller than or equal to `old_layout.size()`"
273         );
274
275         match new_layout.size() {
276             // SAFETY: conditions must be upheld by the caller
277             0 => unsafe {
278                 self.dealloc(ptr, old_layout);
279                 Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0))
280             },
281
282             // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
283             new_size if old_layout.align() == new_layout.align() => unsafe {
284                 // `realloc` probably checks for `new_size <= old_layout.size()` or something similar.
285                 intrinsics::assume(new_size <= old_layout.size());
286
287                 let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size);
288                 let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?;
289                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
290             },
291
292             // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`,
293             // both the old and new memory allocation are valid for reads and writes for `new_size`
294             // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap
295             // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract
296             // for `dealloc` must be upheld by the caller.
297             new_size => unsafe {
298                 let new_ptr = self.alloc(new_layout)?;
299                 ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size);
300                 self.dealloc(ptr, old_layout);
301                 Ok(new_ptr)
302             },
303         }
304     }
305 }
306
307 /// The allocator for unique pointers.
308 // This function must not unwind. If it does, MIR codegen will fail.
309 #[cfg(not(test))]
310 #[lang = "exchange_malloc"]
311 #[inline]
312 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
313     let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
314     match Global.alloc(layout) {
315         Ok(ptr) => ptr.as_mut_ptr(),
316         Err(_) => handle_alloc_error(layout),
317     }
318 }
319
320 #[cfg_attr(not(test), lang = "box_free")]
321 #[inline]
322 // This signature has to be the same as `Box`, otherwise an ICE will happen.
323 // When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as
324 // well.
325 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
326 // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
327 pub(crate) unsafe fn box_free<T: ?Sized, A: AllocRef>(ptr: Unique<T>, alloc: A) {
328     unsafe {
329         let size = size_of_val(ptr.as_ref());
330         let align = min_align_of_val(ptr.as_ref());
331         let layout = Layout::from_size_align_unchecked(size, align);
332         alloc.dealloc(ptr.cast().into(), layout)
333     }
334 }
335
336 // # Allocation error handler
337
338 extern "Rust" {
339     // This is the magic symbol to call the global alloc error handler.  rustc generates
340     // it to call `__rg_oom` if there is a `#[alloc_error_handler]`, or to call the
341     // default implementations below (`__rdl_oom`) otherwise.
342     #[rustc_allocator_nounwind]
343     fn __rust_alloc_error_handler(size: usize, align: usize) -> !;
344 }
345
346 /// Abort on memory allocation error or failure.
347 ///
348 /// Callers of memory allocation APIs wishing to abort computation
349 /// in response to an allocation error are encouraged to call this function,
350 /// rather than directly invoking `panic!` or similar.
351 ///
352 /// The default behavior of this function is to print a message to standard error
353 /// and abort the process.
354 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
355 ///
356 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
357 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
358 #[stable(feature = "global_alloc", since = "1.28.0")]
359 #[cfg(not(any(test, bootstrap)))]
360 #[rustc_allocator_nounwind]
361 pub fn handle_alloc_error(layout: Layout) -> ! {
362     unsafe {
363         __rust_alloc_error_handler(layout.size(), layout.align());
364     }
365 }
366
367 // For alloc test `std::alloc::handle_alloc_error` can be used directly.
368 #[cfg(test)]
369 pub use std::alloc::handle_alloc_error;
370
371 // In stage0 (bootstrap) `__rust_alloc_error_handler`,
372 // might not be generated yet, because an old compiler is used,
373 // so use the old direct call.
374 #[cfg(all(bootstrap, not(test)))]
375 #[stable(feature = "global_alloc", since = "1.28.0")]
376 #[doc(hidden)]
377 #[rustc_allocator_nounwind]
378 pub fn handle_alloc_error(layout: Layout) -> ! {
379     extern "Rust" {
380         #[lang = "oom"]
381         fn oom_impl(layout: Layout) -> !;
382     }
383     unsafe { oom_impl(layout) }
384 }
385
386 #[cfg(not(any(target_os = "hermit", test, bootstrap)))]
387 #[doc(hidden)]
388 #[allow(unused_attributes)]
389 #[unstable(feature = "alloc_internals", issue = "none")]
390 pub mod __alloc_error_handler {
391     use crate::alloc::Layout;
392
393     // called via generated `__rust_alloc_error_handler`
394
395     // if there is no `#[alloc_error_handler]`
396     #[rustc_std_internal_symbol]
397     pub unsafe extern "C" fn __rdl_oom(size: usize, _align: usize) -> ! {
398         panic!("memory allocation of {} bytes failed", size)
399     }
400
401     // if there is a `#[alloc_error_handler]`
402     #[rustc_std_internal_symbol]
403     pub unsafe extern "C" fn __rg_oom(size: usize, align: usize) -> ! {
404         let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
405         extern "Rust" {
406             #[lang = "oom"]
407             fn oom_impl(layout: Layout) -> !;
408         }
409         unsafe { oom_impl(layout) }
410     }
411 }