1 //! A Rust port of the `dlmalloc` allocator.
3 //! The `dlmalloc` allocator is described at
4 //! http://g.oswego.edu/dl/html/malloc.html and this Rust crate is a straight
5 //! port of the C code for the allocator into Rust. The implementation is
6 //! wrapped up in a `Dlmalloc` type and has support for Linux, OSX, and Wasm
9 //! The primary purpose of this crate is that it serves as the default memory
10 //! allocator for the `wasm32-unknown-unknown` target in the standard library.
11 //! Support for other platforms is largely untested and unused, but is used when
12 //! testing this crate.
14 #![cfg_attr(feature = "allocator-api", feature(allocator_api))]
15 #![cfg_attr(target_env = "sgx", feature(asm))]
16 #![cfg_attr(not(feature = "allocator-api"), allow(dead_code))]
18 #![deny(missing_docs)]
20 #[cfg(feature = "allocator-api")]
21 use core
::alloc
::{Alloc, Layout, AllocErr}
;
25 #[cfg(feature = "global")]
26 pub use self::global
::GlobalDlmalloc
;
28 #[cfg(feature = "global")]
32 /// An allocator instance
34 /// Instances of this type are used to allocate blocks of memory. For best
35 /// results only use one of these. Currently doesn't implement `Drop` to release
36 /// lingering memory back to the OS. That may happen eventually though!
37 pub struct Dlmalloc(dlmalloc
::Dlmalloc
);
39 /// Constant initializer for `Dlmalloc` structure.
40 pub const DLMALLOC_INIT
: Dlmalloc
= Dlmalloc(dlmalloc
::DLMALLOC_INIT
);
42 #[cfg(target_arch = "wasm32")]
46 #[cfg(target_os = "macos")]
50 #[cfg(target_os = "linux")]
54 #[cfg(target_env = "sgx")]
59 /// Creates a new instance of an allocator, same as `DLMALLOC_INIT`.
60 pub fn new() -> Dlmalloc
{
64 /// Allocates `size` bytes with `align` align.
66 /// Returns a null pointer if allocation fails. Returns a valid pointer
69 /// Safety and contracts are largely governed by the `GlobalAlloc::alloc`
72 pub unsafe fn malloc(&mut self, size
: usize, align
: usize) -> *mut u8 {
73 if align
<= self.0.malloc_alignment() {
76 self.0.memalign(align
, size
)
80 /// Same as `malloc`, except if the allocation succeeds it's guaranteed to
81 /// point to `size` bytes of zeros.
83 pub unsafe fn calloc(&mut self, size
: usize, align
: usize) -> *mut u8 {
84 let ptr
= self.malloc(size
, align
);
85 if !ptr
.is_null() && self.0.calloc_must_clear(ptr
) {
86 ptr
::write_bytes(ptr
, 0, size
);
91 /// Deallocates a `ptr` with `size` and `align` as the previous request used
94 /// Safety and contracts are largely governed by the `GlobalAlloc::dealloc`
97 pub unsafe fn free(&mut self, ptr
: *mut u8, size
: usize, align
: usize) {
102 /// Reallocates `ptr`, a previous allocation with `old_size` and
103 /// `old_align`, to have `new_size` and the same alignment as before.
105 /// Returns a null pointer if the memory couldn't be reallocated, but `ptr`
106 /// is still valid. Returns a valid pointer and frees `ptr` if the request
109 /// Safety and contracts are largely governed by the `GlobalAlloc::realloc`
110 /// method contracts.
112 pub unsafe fn realloc(&mut self,
116 new_size
: usize) -> *mut u8 {
117 if old_align
<= self.0.malloc_alignment() {
118 self.0.realloc(ptr
, new_size
)
120 let res
= self.malloc(new_size
, old_align
);
122 let size
= cmp
::min(old_size
, new_size
);
123 ptr
::copy_nonoverlapping(ptr
, res
, size
);
124 self.free(ptr
, old_size
, old_align
);
131 #[cfg(feature = "allocator-api")]
132 unsafe impl Alloc
for Dlmalloc
{
137 ) -> Result
<ptr
::NonNull
<u8>, AllocErr
> {
138 let ptr
= <Dlmalloc
>::malloc(self, layout
.size(), layout
.align());
139 ptr
::NonNull
::new(ptr
).ok_or(AllocErr
)
143 unsafe fn dealloc(&mut self, ptr
: ptr
::NonNull
<u8>, layout
: Layout
) {
144 <Dlmalloc
>::free(self, ptr
.as_ptr(), layout
.size(), layout
.align())
150 ptr
: ptr
::NonNull
<u8>,
153 ) -> Result
<ptr
::NonNull
<u8>, AllocErr
> {
154 let ptr
= <Dlmalloc
>::realloc(
161 ptr
::NonNull
::new(ptr
).ok_or(AllocErr
)
165 unsafe fn alloc_zeroed(
168 ) -> Result
<ptr
::NonNull
<u8>, AllocErr
> {
169 let ptr
= <Dlmalloc
>::calloc(self, layout
.size(), layout
.align());
170 ptr
::NonNull
::new(ptr
).ok_or(AllocErr
)