]> git.lizzy.rs Git - rust.git/blob - src/liballoc/alloc.rs
liballoc: apply uniform_paths.
[rust.git] / src / liballoc / alloc.rs
1 //! Memory allocation APIs
2
3 #![stable(feature = "alloc_module", since = "1.28.0")]
4
5 use core::{
6     intrinsics::{min_align_of_val, size_of_val},
7     ptr::{NonNull, Unique},
8     usize,
9 };
10
11 #[stable(feature = "alloc_module", since = "1.28.0")]
12 #[doc(inline)]
13 pub use core::alloc::*;
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     #[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,
27                       old_size: usize,
28                       align: usize,
29                       new_size: usize) -> *mut u8;
30     #[rustc_allocator_nounwind]
31     fn __rust_alloc_zeroed(size: usize, align: usize) -> *mut u8;
32 }
33
34 /// The global memory allocator.
35 ///
36 /// This type implements the [`Alloc`] trait by forwarding calls
37 /// to the allocator registered with the `#[global_allocator]` attribute
38 /// if there is one, or the `std` crate’s default.
39 #[unstable(feature = "allocator_api", issue = "32838")]
40 #[derive(Copy, Clone, Default, Debug)]
41 pub struct Global;
42
43 /// Allocate memory with the global allocator.
44 ///
45 /// This function forwards calls to the [`GlobalAlloc::alloc`] method
46 /// of the allocator registered with the `#[global_allocator]` attribute
47 /// if there is one, or the `std` crate’s default.
48 ///
49 /// This function is expected to be deprecated in favor of the `alloc` method
50 /// of the [`Global`] type when it and the [`Alloc`] trait become stable.
51 ///
52 /// # Safety
53 ///
54 /// See [`GlobalAlloc::alloc`].
55 ///
56 /// # Examples
57 ///
58 /// ```
59 /// use std::alloc::{alloc, dealloc, Layout};
60 ///
61 /// unsafe {
62 ///     let layout = Layout::new::<u16>();
63 ///     let ptr = alloc(layout);
64 ///
65 ///     *(ptr as *mut u16) = 42;
66 ///     assert_eq!(*(ptr as *mut u16), 42);
67 ///
68 ///     dealloc(ptr, layout);
69 /// }
70 /// ```
71 #[stable(feature = "global_alloc", since = "1.28.0")]
72 #[inline]
73 pub unsafe fn alloc(layout: Layout) -> *mut u8 {
74     __rust_alloc(layout.size(), layout.align())
75 }
76
77 /// Deallocate memory with the global allocator.
78 ///
79 /// This function forwards calls to the [`GlobalAlloc::dealloc`] method
80 /// of the allocator registered with the `#[global_allocator]` attribute
81 /// if there is one, or the `std` crate’s default.
82 ///
83 /// This function is expected to be deprecated in favor of the `dealloc` method
84 /// of the [`Global`] type when it and the [`Alloc`] trait become stable.
85 ///
86 /// # Safety
87 ///
88 /// See [`GlobalAlloc::dealloc`].
89 #[stable(feature = "global_alloc", since = "1.28.0")]
90 #[inline]
91 pub unsafe fn dealloc(ptr: *mut u8, layout: Layout) {
92     __rust_dealloc(ptr, layout.size(), layout.align())
93 }
94
95 /// Reallocate memory with the global allocator.
96 ///
97 /// This function forwards calls to the [`GlobalAlloc::realloc`] method
98 /// of the allocator registered with the `#[global_allocator]` attribute
99 /// if there is one, or the `std` crate’s default.
100 ///
101 /// This function is expected to be deprecated in favor of the `realloc` method
102 /// of the [`Global`] type when it and the [`Alloc`] trait become stable.
103 ///
104 /// # Safety
105 ///
106 /// See [`GlobalAlloc::realloc`].
107 #[stable(feature = "global_alloc", since = "1.28.0")]
108 #[inline]
109 pub unsafe fn realloc(ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
110     __rust_realloc(ptr, layout.size(), layout.align(), new_size)
111 }
112
113 /// Allocate zero-initialized memory with the global allocator.
114 ///
115 /// This function forwards calls to the [`GlobalAlloc::alloc_zeroed`] method
116 /// of the allocator registered with the `#[global_allocator]` attribute
117 /// if there is one, or the `std` crate’s default.
118 ///
119 /// This function is expected to be deprecated in favor of the `alloc_zeroed` method
120 /// of the [`Global`] type when it and the [`Alloc`] trait become stable.
121 ///
122 /// # Safety
123 ///
124 /// See [`GlobalAlloc::alloc_zeroed`].
125 ///
126 /// # Examples
127 ///
128 /// ```
129 /// use std::alloc::{alloc_zeroed, dealloc, Layout};
130 ///
131 /// unsafe {
132 ///     let layout = Layout::new::<u16>();
133 ///     let ptr = alloc_zeroed(layout);
134 ///
135 ///     assert_eq!(*(ptr as *mut u16), 0);
136 ///
137 ///     dealloc(ptr, layout);
138 /// }
139 /// ```
140 #[stable(feature = "global_alloc", since = "1.28.0")]
141 #[inline]
142 pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 {
143     __rust_alloc_zeroed(layout.size(), layout.align())
144 }
145
146 #[unstable(feature = "allocator_api", issue = "32838")]
147 unsafe impl Alloc for Global {
148     #[inline]
149     unsafe fn alloc(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
150         NonNull::new(alloc(layout)).ok_or(AllocErr)
151     }
152
153     #[inline]
154     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
155         dealloc(ptr.as_ptr(), layout)
156     }
157
158     #[inline]
159     unsafe fn realloc(&mut self,
160                       ptr: NonNull<u8>,
161                       layout: Layout,
162                       new_size: usize)
163                       -> Result<NonNull<u8>, AllocErr>
164     {
165         NonNull::new(realloc(ptr.as_ptr(), layout, new_size)).ok_or(AllocErr)
166     }
167
168     #[inline]
169     unsafe fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<u8>, AllocErr> {
170         NonNull::new(alloc_zeroed(layout)).ok_or(AllocErr)
171     }
172 }
173
174 /// The allocator for unique pointers.
175 // This function must not unwind. If it does, MIR codegen will fail.
176 #[cfg(not(test))]
177 #[lang = "exchange_malloc"]
178 #[inline]
179 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
180     if size == 0 {
181         align as *mut u8
182     } else {
183         let layout = Layout::from_size_align_unchecked(size, align);
184         let ptr = alloc(layout);
185         if !ptr.is_null() {
186             ptr
187         } else {
188             handle_alloc_error(layout)
189         }
190     }
191 }
192
193 #[cfg_attr(not(test), lang = "box_free")]
194 #[inline]
195 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
196     let ptr = ptr.as_ptr();
197     let size = size_of_val(&*ptr);
198     let align = min_align_of_val(&*ptr);
199     // We do not allocate for Box<T> when T is ZST, so deallocation is also not necessary.
200     if size != 0 {
201         let layout = Layout::from_size_align_unchecked(size, align);
202         dealloc(ptr as *mut u8, layout);
203     }
204 }
205
206 /// Abort on memory allocation error or failure.
207 ///
208 /// Callers of memory allocation APIs wishing to abort computation
209 /// in response to an allocation error are encouraged to call this function,
210 /// rather than directly invoking `panic!` or similar.
211 ///
212 /// The default behavior of this function is to print a message to standard error
213 /// and abort the process.
214 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
215 ///
216 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
217 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
218 #[stable(feature = "global_alloc", since = "1.28.0")]
219 #[rustc_allocator_nounwind]
220 pub fn handle_alloc_error(layout: Layout) -> ! {
221     #[allow(improper_ctypes)]
222     extern "Rust" {
223         #[lang = "oom"]
224         fn oom_impl(layout: Layout) -> !;
225     }
226     unsafe { oom_impl(layout) }
227 }
228
229 #[cfg(test)]
230 mod tests {
231     extern crate test;
232     use test::Bencher;
233     use crate::{
234         boxed::Box,
235         alloc::{Global, Alloc, Layout, handle_alloc_error},
236     };
237
238     #[test]
239     fn allocate_zeroed() {
240         unsafe {
241             let layout = Layout::from_size_align(1024, 1).unwrap();
242             let ptr = Global.alloc_zeroed(layout.clone())
243                 .unwrap_or_else(|_| handle_alloc_error(layout));
244
245             let mut i = ptr.cast::<u8>().as_ptr();
246             let end = i.add(layout.size());
247             while i < end {
248                 assert_eq!(*i, 0);
249                 i = i.offset(1);
250             }
251             Global.dealloc(ptr, layout);
252         }
253     }
254
255     #[bench]
256     fn alloc_owned_small(b: &mut Bencher) {
257         b.iter(|| {
258             let _: Box<_> = box 10;
259         })
260     }
261 }