]> git.lizzy.rs Git - rust.git/blob - library/alloc/src/alloc.rs
Fix font color for help button in ayu and dark themes
[rust.git] / library / alloc / src / 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     unsafe { __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     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 ///
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     unsafe { __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     unsafe { __rust_alloc_zeroed(layout.size(), layout.align()) }
162 }
163
164 impl Global {
165     #[inline]
166     fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result<NonNull<[u8]>, AllocErr> {
167         match layout.size() {
168             0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)),
169             // SAFETY: `layout` is non-zero in size,
170             size => unsafe {
171                 let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) };
172                 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
173                 Ok(NonNull::slice_from_raw_parts(ptr, size))
174             },
175         }
176     }
177
178     // Safety: Same as `AllocRef::grow`
179     #[inline]
180     unsafe fn grow_impl(
181         &mut self,
182         ptr: NonNull<u8>,
183         layout: Layout,
184         new_size: usize,
185         zeroed: bool,
186     ) -> Result<NonNull<[u8]>, AllocErr> {
187         debug_assert!(
188             new_size >= layout.size(),
189             "`new_size` must be greater than or equal to `layout.size()`"
190         );
191
192         match layout.size() {
193             // SAFETY: the caller must ensure that the `new_size` does not overflow.
194             // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout.
195             0 => unsafe {
196                 let new_layout = Layout::from_size_align_unchecked(new_size, layout.align());
197                 self.alloc_impl(new_layout, zeroed)
198             },
199
200             // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size`
201             // as required by safety conditions. Other conditions must be upheld by the caller
202             old_size => unsafe {
203                 // `realloc` probably checks for `new_size >= size` or something similar.
204                 intrinsics::assume(new_size >= layout.size());
205
206                 let raw_ptr = realloc(ptr.as_ptr(), layout, new_size);
207                 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
208                 if zeroed {
209                     raw_ptr.add(old_size).write_bytes(0, new_size - old_size);
210                 }
211                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
212             },
213         }
214     }
215 }
216
217 #[unstable(feature = "allocator_api", issue = "32838")]
218 unsafe impl AllocRef for Global {
219     #[inline]
220     fn alloc(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
221         self.alloc_impl(layout, false)
222     }
223
224     #[inline]
225     fn alloc_zeroed(&mut self, layout: Layout) -> Result<NonNull<[u8]>, AllocErr> {
226         self.alloc_impl(layout, true)
227     }
228
229     #[inline]
230     unsafe fn dealloc(&mut self, ptr: NonNull<u8>, layout: Layout) {
231         if layout.size() != 0 {
232             // SAFETY: `layout` is non-zero in size,
233             // other conditions must be upheld by the caller
234             unsafe { dealloc(ptr.as_ptr(), layout) }
235         }
236     }
237
238     #[inline]
239     unsafe fn grow(
240         &mut self,
241         ptr: NonNull<u8>,
242         layout: Layout,
243         new_size: usize,
244     ) -> Result<NonNull<[u8]>, AllocErr> {
245         // SAFETY: all conditions must be upheld by the caller
246         unsafe { self.grow_impl(ptr, layout, new_size, false) }
247     }
248
249     #[inline]
250     unsafe fn grow_zeroed(
251         &mut self,
252         ptr: NonNull<u8>,
253         layout: Layout,
254         new_size: usize,
255     ) -> Result<NonNull<[u8]>, AllocErr> {
256         // SAFETY: all conditions must be upheld by the caller
257         unsafe { self.grow_impl(ptr, layout, new_size, true) }
258     }
259
260     #[inline]
261     unsafe fn shrink(
262         &mut self,
263         ptr: NonNull<u8>,
264         layout: Layout,
265         new_size: usize,
266     ) -> Result<NonNull<[u8]>, AllocErr> {
267         debug_assert!(
268             new_size <= layout.size(),
269             "`new_size` must be smaller than or equal to `layout.size()`"
270         );
271
272         match new_size {
273             // SAFETY: conditions must be upheld by the caller
274             0 => unsafe {
275                 self.dealloc(ptr, layout);
276                 Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0))
277             },
278
279             // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller
280             new_size => unsafe {
281                 // `realloc` probably checks for `new_size <= size` or something similar.
282                 intrinsics::assume(new_size <= layout.size());
283
284                 let raw_ptr = realloc(ptr.as_ptr(), layout, new_size);
285                 let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?;
286                 Ok(NonNull::slice_from_raw_parts(ptr, new_size))
287             },
288         }
289     }
290 }
291
292 /// The allocator for unique pointers.
293 // This function must not unwind. If it does, MIR codegen will fail.
294 #[cfg(not(test))]
295 #[lang = "exchange_malloc"]
296 #[inline]
297 unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 {
298     let layout = unsafe { Layout::from_size_align_unchecked(size, align) };
299     match Global.alloc(layout) {
300         Ok(ptr) => ptr.as_non_null_ptr().as_ptr(),
301         Err(_) => handle_alloc_error(layout),
302     }
303 }
304
305 #[cfg_attr(not(test), lang = "box_free")]
306 #[inline]
307 // This signature has to be the same as `Box`, otherwise an ICE will happen.
308 // When an additional parameter to `Box` is added (like `A: AllocRef`), this has to be added here as
309 // well.
310 // For example if `Box` is changed to  `struct Box<T: ?Sized, A: AllocRef>(Unique<T>, A)`,
311 // this function has to be changed to `fn box_free<T: ?Sized, A: AllocRef>(Unique<T>, A)` as well.
312 pub(crate) unsafe fn box_free<T: ?Sized>(ptr: Unique<T>) {
313     unsafe {
314         let size = size_of_val(ptr.as_ref());
315         let align = min_align_of_val(ptr.as_ref());
316         let layout = Layout::from_size_align_unchecked(size, align);
317         Global.dealloc(ptr.cast().into(), layout)
318     }
319 }
320
321 /// Abort on memory allocation error or failure.
322 ///
323 /// Callers of memory allocation APIs wishing to abort computation
324 /// in response to an allocation error are encouraged to call this function,
325 /// rather than directly invoking `panic!` or similar.
326 ///
327 /// The default behavior of this function is to print a message to standard error
328 /// and abort the process.
329 /// It can be replaced with [`set_alloc_error_hook`] and [`take_alloc_error_hook`].
330 ///
331 /// [`set_alloc_error_hook`]: ../../std/alloc/fn.set_alloc_error_hook.html
332 /// [`take_alloc_error_hook`]: ../../std/alloc/fn.take_alloc_error_hook.html
333 #[stable(feature = "global_alloc", since = "1.28.0")]
334 #[rustc_allocator_nounwind]
335 pub fn handle_alloc_error(layout: Layout) -> ! {
336     extern "Rust" {
337         #[lang = "oom"]
338         fn oom_impl(layout: Layout) -> !;
339     }
340     unsafe { oom_impl(layout) }
341 }