gear_dlmalloc/lib.rs
1//! A Rust port of the `dlmalloc` allocator.
2//!
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
7//! currently.
8//!
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.
13
14#![no_std]
15#![deny(missing_docs)]
16#![allow(dead_code)]
17#![allow(clippy::missing_safety_doc)]
18
19use core::cmp;
20use core::ptr;
21
22mod common;
23mod dlmalloc;
24mod dlverbose;
25
26#[cfg(all(feature = "global", not(test)))]
27mod global;
28#[cfg(all(feature = "global", not(test)))]
29pub use self::global::GlobalDlmalloc;
30#[cfg(all(feature = "global", not(test)))]
31pub use global::get_alloced_mem_size;
32
33/// An allocator instance
34///
35/// Instances of this type are used to allocate blocks of memory. For best
36/// results only use one of these. Currently doesn't implement `Drop` to release
37/// lingering memory back to the OS. That may happen eventually though!
38pub struct Dlmalloc(dlmalloc::Dlmalloc);
39
40/// Constant initializer for `Dlmalloc` structure.
41pub const DLMALLOC_INIT: Dlmalloc = Dlmalloc(dlmalloc::DLMALLOC_INIT);
42
43#[cfg(target_arch = "wasm32")]
44#[path = "wasm.rs"]
45mod sys;
46
47#[cfg(target_os = "macos")]
48#[path = "macos.rs"]
49mod sys;
50
51#[cfg(target_os = "linux")]
52#[path = "linux.rs"]
53mod sys;
54
55#[cfg(target_os = "windows")]
56#[path = "windows.rs"]
57mod sys;
58
59#[allow(clippy::new_without_default)]
60impl Dlmalloc {
61 /// Creates a new instance of an allocator, same as `DLMALLOC_INIT`.
62 pub fn new() -> Dlmalloc {
63 DLMALLOC_INIT
64 }
65
66 /// Allocates `size` bytes with `align` align.
67 ///
68 /// Returns a null pointer if allocation fails. Returns a valid pointer
69 /// otherwise.
70 ///
71 /// Safety and contracts are largely governed by the `GlobalAlloc::alloc`
72 /// method contracts.
73 #[inline]
74 pub unsafe fn malloc(&mut self, size: usize, align: usize) -> *mut u8 {
75 if align <= self.0.malloc_alignment() {
76 self.0.malloc(size)
77 } else {
78 self.0.memalign(align, size)
79 }
80 }
81
82 /// Same as `malloc`, except if the allocation succeeds it's guaranteed to
83 /// point to `size` bytes of zeros.
84 #[inline]
85 pub unsafe fn calloc(&mut self, size: usize, align: usize) -> *mut u8 {
86 dlverbose!("DL CALLOC");
87 let ptr = self.malloc(size, align);
88 if !ptr.is_null() {
89 ptr::write_bytes(ptr, 0, size);
90 }
91 ptr
92 }
93
94 /// Deallocates a `ptr` with `size` and `align` as the previous request used
95 /// to allocate it.
96 ///
97 /// Safety and contracts are largely governed by the `GlobalAlloc::dealloc`
98 /// method contracts.
99 #[inline]
100 pub unsafe fn free(&mut self, ptr: *mut u8, _size: usize, _align: usize) {
101 self.0.free(ptr)
102 }
103
104 /// Reallocates `ptr`, a previous allocation with `old_size` and
105 /// `old_align`, to have `new_size` and the same alignment as before.
106 ///
107 /// Returns a null pointer if the memory couldn't be reallocated, but `ptr`
108 /// is still valid. Returns a valid pointer and frees `ptr` if the request
109 /// is satisfied.
110 ///
111 /// Safety and contracts are largely governed by the `GlobalAlloc::realloc`
112 /// method contracts.
113 #[inline]
114 pub unsafe fn realloc(
115 &mut self,
116 ptr: *mut u8,
117 old_size: usize,
118 old_align: usize,
119 new_size: usize,
120 ) -> *mut u8 {
121 if old_align <= self.0.malloc_alignment() {
122 self.0.realloc(ptr, new_size)
123 } else {
124 let res = self.malloc(new_size, old_align);
125 if !res.is_null() {
126 let size = cmp::min(old_size, new_size);
127 ptr::copy_nonoverlapping(ptr, res, size);
128 self.free(ptr, old_size, old_align);
129 }
130 res
131 }
132 }
133
134 /// Returns alloced mem size
135 pub unsafe fn get_alloced_mem_size(&self) -> usize {
136 self.0.get_alloced_mem_size()
137 }
138}