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