isoalloc/
lib.rs

1#![no_std]
2#![allow(non_snake_case, non_camel_case_types)]
3extern crate libisoalloc_sys as ffi;
4
5use core::alloc::{GlobalAlloc, Layout};
6use core::ffi::c_void;
7use ffi::*;
8
9pub struct IsoAlloc;
10
11/// As part of isoalloc security's makeup, addresses are 8 bytes aligned.
12unsafe impl GlobalAlloc for IsoAlloc {
13    #[inline]
14    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
15        iso_alloc(layout.size()) as *mut u8
16    }
17
18    #[inline]
19    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
20        iso_calloc(1usize, layout.size()) as *mut u8
21    }
22
23    #[inline]
24    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
25        iso_free_size(ptr as *mut c_void, layout.size());
26    }
27
28    #[inline]
29    unsafe fn realloc(&self, ptr: *mut u8, _: Layout, size: usize) -> *mut u8 {
30        iso_realloc(ptr as *mut c_void, size) as *mut u8
31    }
32}
33
34impl IsoAlloc {
35    /// creates a block of nmemb * size.
36    ///
37    /// # Safety
38    ///
39    /// it also checks for overflow, similar as `realloc` otherwise.
40    pub unsafe fn reallocarray(
41        &self,
42        ptr: *mut u8,
43        _: Layout,
44        nmemb: usize,
45        size: usize,
46    ) -> *mut u8 {
47        iso_reallocarray(ptr as *mut c_void, nmemb, size) as *mut u8
48    }
49
50    /// `malloc_usable_size` like call.
51    pub fn usable_size(&self, ptr: *mut u8) -> usize {
52        unsafe { iso_chunksz(ptr as *mut c_void) }
53    }
54
55    /// checks zones coherency.
56    pub fn verify_zones(&self) {
57        unsafe { iso_verify_zones() };
58    }
59
60    /// fetches peak memory usage.
61    pub fn mem_usage(&self) -> u64 {
62        unsafe { iso_alloc_mem_usage() }
63    }
64
65    /// memory leaks.
66    pub fn leaks(&self) -> u64 {
67        unsafe { iso_alloc_detect_leaks() }
68    }
69
70    fn page_size(&self) -> u64 {
71        static HDL: spin::Once = spin::Once::new();
72        static mut PSZ: u64 = 0;
73
74        unsafe {
75            HDL.call_once(|| PSZ = libc::sysconf(libc::_SC_PAGESIZE) as u64);
76            PSZ
77        }
78    }
79
80    pub fn IS_PAGE_ALIGNED(&self, p: u64) -> bool {
81        p & (self.page_size() - 1) == 0
82    }
83
84    pub const fn IS_ALIGNED(&self, p: u64) -> bool {
85        p & (8 - 1) == 0
86    }
87}
88
89#[cfg(test)]
90mod tests {
91    use super::*;
92
93    #[test]
94    fn reuse_mem() {
95        unsafe {
96            let l = Layout::from_size_align(1024, 8)
97                .expect("should be able to work 8 with bytes alignment");
98            let mut p = IsoAlloc.alloc_zeroed(l);
99            p = IsoAlloc.realloc(p, l, 4096);
100            assert!(IsoAlloc.IS_ALIGNED(p as u64));
101            IsoAlloc.dealloc(p, l);
102        }
103    }
104
105    #[test]
106    fn large_alloc() {
107        unsafe {
108            let l = Layout::from_size_align(1 << 20, 32).unwrap();
109            let p = IsoAlloc.alloc(l);
110            assert!(IsoAlloc.IS_PAGE_ALIGNED(p as u64));
111            IsoAlloc.dealloc(p, l);
112        }
113    }
114
115    #[test]
116    fn realloc_array() {
117        unsafe {
118            let l = Layout::from_size_align(8, 8).unwrap();
119            let mut p = core::ptr::null_mut();
120            p = IsoAlloc.realloc(p, l, 1024);
121            p = IsoAlloc.reallocarray(p, l, 2, 1024);
122            IsoAlloc.dealloc(p, l);
123        }
124    }
125
126    #[test]
127    fn utils() {
128        use core::convert::TryInto;
129        unsafe {
130            let l = Layout::from_size_align(8, 8).unwrap();
131            let a = IsoAlloc.alloc(l);
132            assert!(IsoAlloc.usable_size(a) >= l.size());
133            let ta = IsoAlloc.mem_usage();
134            assert!(ta > l.size().try_into().unwrap());
135            let b = IsoAlloc.alloc(l);
136            let tb = IsoAlloc.mem_usage();
137            assert!(tb >= ta);
138            IsoAlloc.dealloc(b, l);
139            IsoAlloc.dealloc(a, l);
140            assert_eq!(IsoAlloc.leaks(), 0u64);
141            IsoAlloc.verify_zones();
142        }
143    }
144}