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}