use crate::allocator::passthrough;
use crate::init::{self, STATE_READY};
use core::ffi::c_void;
use core::ptr;
macro_rules! dispatch {
($hardened_fn:expr, $passthrough_fn:expr) => {{
if init::state() == STATE_READY {
$hardened_fn
} else {
#[cold]
#[inline(never)]
unsafe fn slow_init() {
init::ensure_initialized();
}
slow_init();
if init::state() == STATE_READY {
$hardened_fn
} else {
$passthrough_fn
}
}
}};
}
#[inline(always)]
unsafe fn enomem_on_null(ptr: *mut c_void) -> *mut c_void {
if ptr.is_null() {
*libc::__errno_location() = libc::ENOMEM;
}
ptr
}
#[no_mangle]
pub unsafe extern "C" fn malloc(size: usize) -> *mut c_void {
enomem_on_null(dispatch!(
init::allocator().malloc(size) as *mut c_void,
passthrough::malloc(size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn free(ptr: *mut c_void) {
if ptr.is_null() {
return;
}
dispatch!(
init::allocator().free(ptr as *mut u8),
passthrough::free(ptr as *mut u8)
);
}
#[no_mangle]
pub unsafe extern "C" fn realloc(ptr: *mut c_void, size: usize) -> *mut c_void {
enomem_on_null(dispatch!(
init::allocator().realloc(ptr as *mut u8, size) as *mut c_void,
passthrough::realloc(ptr as *mut u8, size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn calloc(nmemb: usize, size: usize) -> *mut c_void {
enomem_on_null(dispatch!(
init::allocator().calloc(nmemb, size) as *mut c_void,
passthrough::calloc(nmemb, size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn posix_memalign(
memptr: *mut *mut c_void,
alignment: usize,
size: usize,
) -> libc::c_int {
if memptr.is_null() {
return libc::EINVAL;
}
if !alignment.is_power_of_two() || alignment < core::mem::size_of::<*mut c_void>() {
return libc::EINVAL;
}
let ptr = dispatch!(
init::allocator().memalign(alignment, size) as *mut c_void,
passthrough::memalign(alignment, size) as *mut c_void
);
if ptr.is_null() {
return libc::ENOMEM;
}
*memptr = ptr;
0
}
#[no_mangle]
pub unsafe extern "C" fn aligned_alloc(alignment: usize, size: usize) -> *mut c_void {
if !alignment.is_power_of_two() || (!size.is_multiple_of(alignment) && size != 0) {
*libc::__errno_location() = libc::EINVAL;
return ptr::null_mut();
}
enomem_on_null(dispatch!(
init::allocator().memalign(alignment, size) as *mut c_void,
passthrough::memalign(alignment, size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn memalign(alignment: usize, size: usize) -> *mut c_void {
enomem_on_null(dispatch!(
init::allocator().memalign(alignment, size) as *mut c_void,
passthrough::memalign(alignment, size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn valloc(size: usize) -> *mut c_void {
let ps = crate::util::page_size();
enomem_on_null(dispatch!(
init::allocator().memalign(ps, size) as *mut c_void,
passthrough::memalign(ps, size) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn pvalloc(size: usize) -> *mut c_void {
let ps = crate::util::page_size();
let rounded = crate::util::align_up(size, ps);
enomem_on_null(dispatch!(
init::allocator().memalign(ps, rounded) as *mut c_void,
passthrough::memalign(ps, rounded) as *mut c_void
))
}
#[no_mangle]
pub unsafe extern "C" fn malloc_usable_size(ptr: *mut c_void) -> usize {
if ptr.is_null() {
return 0;
}
dispatch!(
init::allocator().usable_size(ptr as *mut u8),
passthrough::malloc_usable_size(ptr as *mut u8)
)
}
#[no_mangle]
pub unsafe extern "C" fn mallopt(_param: libc::c_int, _value: libc::c_int) -> libc::c_int {
1
}
#[cfg(not(target_env = "musl"))]
#[no_mangle]
pub unsafe extern "C" fn mallinfo() -> libc::mallinfo {
core::mem::zeroed()
}
#[cfg(all(target_os = "linux", not(target_env = "musl")))]
#[no_mangle]
pub unsafe extern "C" fn mallinfo2() -> libc::mallinfo2 {
core::mem::zeroed()
}
#[no_mangle]
pub unsafe extern "C" fn compatmalloc_check_integrity() -> libc::c_int {
if init::state() != STATE_READY {
return 0;
}
let result = init::allocator().check_integrity();
result.errors_found as libc::c_int
}