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