blob: b9aba1e9cab321d979430c921d3960cfacf38ac3 [file] [log] [blame]
Alex Crichton695dee02017-06-03 21:54:081// Copyright 2017 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
Simon Sapine9fd0632018-05-31 16:23:4211//! Memory allocation APIs
Simon Sapina24924f2018-05-31 18:22:5912//!
13//! In a given program, the standard library has one “global” memory allocator
14//! that is used for example by `Box<T>` and `Vec<T>`.
15//!
16//! Currently the default global allocator is unspecified.
17//! The compiler may link to a version of [jemalloc] on some platforms,
18//! but this is not guaranteed.
19//! Libraries, however, like `cdylib`s and `staticlib`s are guaranteed
20//! to use the [`System`] by default.
21//!
22//! [jemalloc]: https://github.com/jemalloc/jemalloc
23//! [`System`]: struct.System.html
24//!
25//! # The `#[global_allocator]` attribute
26//!
27//! This attribute allows configuring the choice of global allocator.
28//! You can use this to implement a completely custom global allocator
29//! to route all default allocation requests to a custom object.
30//!
31//! ```rust
32//! use std::alloc::{GlobalAlloc, System, Layout};
33//!
34//! struct MyAllocator;
35//!
36//! unsafe impl GlobalAlloc for MyAllocator {
37//! unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
38//! System.alloc(layout)
39//! }
40//!
41//! unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
42//! System.dealloc(ptr, layout)
43//! }
44//! }
45//!
46//! #[global_allocator]
47//! static GLOBAL: MyAllocator = MyAllocator;
48//!
49//! fn main() {
50//! // This `Vec` will allocate memory through `GLOBAL` above
51//! let mut v = Vec::new();
52//! v.push(1);
53//! }
54//! ```
55//!
56//! The attribute is used on a `static` item whose type implements the
57//! [`GlobalAlloc`] trait. This type can be provided by an external library:
58//!
59//! [`GlobalAlloc`]: ../../core/alloc/trait.GlobalAlloc.html
60//!
61//! ```rust,ignore (demonstrates crates.io usage)
62//! extern crate jemallocator;
63//!
Ixrecd6cf1822018-06-29 02:12:0264//! use jemallocator::Jemalloc;
Simon Sapina24924f2018-05-31 18:22:5965//!
66//! #[global_allocator]
67//! static GLOBAL: Jemalloc = Jemalloc;
68//!
69//! fn main() {}
70//! ```
71//!
72//! The `#[global_allocator]` can only be used once in a crate
73//! or its recursive dependencies.
Alex Crichton695dee02017-06-03 21:54:0874
Simon Sapin951bc282018-05-31 16:36:5175#![stable(feature = "alloc_module", since = "1.28.0")]
Alex Crichton695dee02017-06-03 21:54:0876
Mike Hommeya4d899b2018-05-16 00:16:3777use core::sync::atomic::{AtomicPtr, Ordering};
78use core::{mem, ptr};
Mike Hommeyb945be72018-05-31 23:50:0779use sys_common::util::dumb_print;
Mike Hommeya4d899b2018-05-16 00:16:3780
Simon Sapin951bc282018-05-31 16:36:5181#[stable(feature = "alloc_module", since = "1.28.0")]
82#[doc(inline)]
83pub use alloc_crate::alloc::*;
84
Simon Sapin81117172018-05-31 17:16:2485#[stable(feature = "alloc_system_type", since = "1.28.0")]
Simon Sapin951bc282018-05-31 16:36:5186#[doc(inline)]
87pub use alloc_system::System;
88
Mike Hommeya4d899b2018-05-16 00:16:3789static HOOK: AtomicPtr<()> = AtomicPtr::new(ptr::null_mut());
90
Simon Sapin2b789bd2018-06-13 22:32:3091/// Registers a custom allocation error hook, replacing any that was previously registered.
Mike Hommeya4d899b2018-05-16 00:16:3792///
Simon Sapin2b789bd2018-06-13 22:32:3093/// The allocation error hook is invoked when an infallible memory allocation fails, before
Mike Hommeyb945be72018-05-31 23:50:0794/// the runtime aborts. The default hook prints a message to standard error,
Simon Sapin2b789bd2018-06-13 22:32:3095/// but this behavior can be customized with the [`set_alloc_error_hook`] and
96/// [`take_alloc_error_hook`] functions.
Mike Hommeya4d899b2018-05-16 00:16:3797///
98/// The hook is provided with a `Layout` struct which contains information
99/// about the allocation that failed.
100///
Simon Sapin2b789bd2018-06-13 22:32:30101/// The allocation error hook is a global resource.
102#[unstable(feature = "alloc_error_hook", issue = "51245")]
103pub fn set_alloc_error_hook(hook: fn(Layout)) {
Mike Hommeya4d899b2018-05-16 00:16:37104 HOOK.store(hook as *mut (), Ordering::SeqCst);
105}
106
Simon Sapin2b789bd2018-06-13 22:32:30107/// Unregisters the current allocation error hook, returning it.
Mike Hommeya4d899b2018-05-16 00:16:37108///
Simon Sapin2b789bd2018-06-13 22:32:30109/// *See also the function [`set_alloc_error_hook`].*
Mike Hommeya4d899b2018-05-16 00:16:37110///
111/// If no custom hook is registered, the default hook will be returned.
Simon Sapin2b789bd2018-06-13 22:32:30112#[unstable(feature = "alloc_error_hook", issue = "51245")]
113pub fn take_alloc_error_hook() -> fn(Layout) {
Mike Hommeya4d899b2018-05-16 00:16:37114 let hook = HOOK.swap(ptr::null_mut(), Ordering::SeqCst);
115 if hook.is_null() {
Simon Sapin2b789bd2018-06-13 22:32:30116 default_alloc_error_hook
Mike Hommeya4d899b2018-05-16 00:16:37117 } else {
118 unsafe { mem::transmute(hook) }
119 }
120}
121
Simon Sapin2b789bd2018-06-13 22:32:30122fn default_alloc_error_hook(layout: Layout) {
Mike Hommeyb945be72018-05-31 23:50:07123 dumb_print(format_args!("memory allocation of {} bytes failed", layout.size()));
Mike Hommeya4d899b2018-05-16 00:16:37124}
125
Steven Facklere513c1b2018-04-21 04:05:13126#[cfg(not(test))]
127#[doc(hidden)]
Mark Rousskov683a3db2018-08-01 13:37:38128#[alloc_error_handler]
Simon Sapin75e17da2018-05-31 16:38:39129#[unstable(feature = "alloc_internals", issue = "0")]
Simon Sapin620599e2018-07-08 14:07:08130pub fn rust_oom(layout: Layout) -> ! {
Mike Hommeya4d899b2018-05-16 00:16:37131 let hook = HOOK.load(Ordering::SeqCst);
Mike Hommeyb945be72018-05-31 23:50:07132 let hook: fn(Layout) = if hook.is_null() {
Simon Sapin2b789bd2018-06-13 22:32:30133 default_alloc_error_hook
Mike Hommeya4d899b2018-05-16 00:16:37134 } else {
135 unsafe { mem::transmute(hook) }
136 };
Mike Hommeyb945be72018-05-31 23:50:07137 hook(layout);
138 unsafe { ::sys::abort_internal(); }
Steven Facklere513c1b2018-04-21 04:05:13139}
140
Alex Crichton90105672017-07-17 16:32:08141#[cfg(not(test))]
Alex Crichton695dee02017-06-03 21:54:08142#[doc(hidden)]
Alex Crichtonfbf98692017-11-01 20:16:36143#[allow(unused_attributes)]
Simon Sapin75e17da2018-05-31 16:38:39144#[unstable(feature = "alloc_internals", issue = "0")]
Alex Crichton695dee02017-06-03 21:54:08145pub mod __default_lib_allocator {
Mike Hommeyf6ab74b2018-05-31 06:57:43146 use super::{System, Layout, GlobalAlloc};
Alex Crichton695dee02017-06-03 21:54:08147 // for symbol names src/librustc/middle/allocator.rs
148 // for signatures src/librustc_allocator/lib.rs
149
150 // linkage directives are provided as part of the current compiler allocator
151 // ABI
152
153 #[no_mangle]
Alex Crichtonfbf98692017-11-01 20:16:36154 #[rustc_std_internal_symbol]
Simon Sapin86753ce2018-04-03 15:12:57155 pub unsafe extern fn __rdl_alloc(size: usize, align: usize) -> *mut u8 {
Alex Crichton695dee02017-06-03 21:54:08156 let layout = Layout::from_size_align_unchecked(size, align);
Mike Hommeyf6ab74b2018-05-31 06:57:43157 System.alloc(layout)
Alex Crichton695dee02017-06-03 21:54:08158 }
159
Simon Sapineae0d462018-04-04 16:57:48160 #[no_mangle]
161 #[rustc_std_internal_symbol]
Alex Crichton695dee02017-06-03 21:54:08162 pub unsafe extern fn __rdl_dealloc(ptr: *mut u8,
163 size: usize,
164 align: usize) {
Mike Hommeyf6ab74b2018-05-31 06:57:43165 System.dealloc(ptr, Layout::from_size_align_unchecked(size, align))
Alex Crichton695dee02017-06-03 21:54:08166 }
167
168 #[no_mangle]
Alex Crichtonfbf98692017-11-01 20:16:36169 #[rustc_std_internal_symbol]
Alex Crichton695dee02017-06-03 21:54:08170 pub unsafe extern fn __rdl_realloc(ptr: *mut u8,
171 old_size: usize,
Simon Sapin86753ce2018-04-03 15:12:57172 align: usize,
173 new_size: usize) -> *mut u8 {
174 let old_layout = Layout::from_size_align_unchecked(old_size, align);
Mike Hommeyf6ab74b2018-05-31 06:57:43175 System.realloc(ptr, old_layout, new_size)
Alex Crichton695dee02017-06-03 21:54:08176 }
177
178 #[no_mangle]
Alex Crichtonfbf98692017-11-01 20:16:36179 #[rustc_std_internal_symbol]
Simon Sapin86753ce2018-04-03 15:12:57180 pub unsafe extern fn __rdl_alloc_zeroed(size: usize, align: usize) -> *mut u8 {
Alex Crichton695dee02017-06-03 21:54:08181 let layout = Layout::from_size_align_unchecked(size, align);
Mike Hommeyf6ab74b2018-05-31 06:57:43182 System.alloc_zeroed(layout)
Alex Crichton695dee02017-06-03 21:54:08183 }
Alex Crichton695dee02017-06-03 21:54:08184}