rs_libc/
alloc.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7use std::alloc::{GlobalAlloc, Layout, System};
8use std::ffi::c_void;
9use std::mem;
10use std::ptr;
11
12#[allow(non_camel_case_types)]
13pub(crate) type size_t = usize;
14const ALIGN: usize = 8;
15
16// We purposefully mangle symbols, when compiling for test to avoid collision
17// with libc.a
18#[cfg_attr(not(test), no_mangle)]
19pub unsafe extern "C" fn malloc(size: size_t) -> *mut c_void {
20    let ptr_size = mem::size_of::<*mut usize>();
21    let alloc_size = size + ptr_size;
22    let alloc_layout = Layout::from_size_align_unchecked(alloc_size, ALIGN);
23    let ptr = System.alloc(alloc_layout) as *mut usize;
24    if ptr == ptr::null_mut() {
25        return ptr::null_mut();
26    }
27    ptr::write(ptr, alloc_size);
28    ptr.offset(1) as *mut c_void
29}
30
31#[cfg_attr(not(test), no_mangle)]
32pub unsafe extern "C" fn calloc(n: size_t, size: size_t) -> *mut c_void {
33    let ptr_size = mem::size_of::<*mut usize>();
34    let alloc_size = (n * size) + ptr_size;
35    let alloc_layout = Layout::from_size_align_unchecked(alloc_size, ALIGN);
36    let ptr = System.alloc_zeroed(alloc_layout) as *mut usize;
37    if ptr == ptr::null_mut() {
38        return ptr::null_mut();
39    }
40    ptr::write(ptr, alloc_size);
41    ptr.offset(1) as *mut c_void
42}
43
44#[cfg_attr(not(test), no_mangle)]
45pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: size_t) -> *mut c_void {
46    if ptr == ptr::null_mut() {
47        return malloc(size);
48    } else if size == 0 {
49        free(ptr);
50        return ptr::null_mut();
51    }
52
53    let ptr = (ptr as *mut usize).offset(-1);
54    let ptr_size = mem::size_of::<*mut usize>();
55    let old_alloc_layout = Layout::from_size_align_unchecked(ptr::read(ptr), ALIGN);
56    let new_alloc_size = size + ptr_size;
57
58    let ptr = System.realloc(ptr as _, old_alloc_layout, new_alloc_size) as *mut usize;
59    if ptr == ptr::null_mut() {
60        return ptr::null_mut();
61    }
62
63    ptr::write(ptr, new_alloc_size);
64    ptr.offset(1) as *mut c_void
65}
66
67#[cfg_attr(not(test), no_mangle)]
68pub unsafe extern "C" fn free(ptr: *mut c_void) {
69    if ptr == ptr::null_mut() {
70        return;
71    }
72    let ptr = (ptr as *mut usize).offset(-1);
73    let alloc_layout = Layout::from_size_align_unchecked(ptr::read(ptr), ALIGN);
74    System.dealloc(ptr as *mut u8, alloc_layout);
75}
76
77#[cfg(test)]
78mod tests {
79
80    // Below test verifies that from_size_align does not return an error.
81    use super::ALIGN;
82    use std::alloc::Layout;
83    #[test]
84    fn test_layout_unwrap() {
85        let _ = Layout::from_size_align(1, ALIGN).unwrap();
86        let _ = Layout::from_size_align(7, ALIGN).unwrap();
87        let _ = Layout::from_size_align(1025, ALIGN).unwrap();
88    }
89}