use core::ffi::c_void;
use core::ptr;
use core::sync::atomic::{AtomicUsize, Ordering};
type MallocFn = unsafe extern "C" fn(usize) -> *mut c_void;
type FreeFn = unsafe extern "C" fn(*mut c_void);
type ReallocFn = unsafe extern "C" fn(*mut c_void, usize) -> *mut c_void;
type CallocFn = unsafe extern "C" fn(usize, usize) -> *mut c_void;
type PosixMemalignFn = unsafe extern "C" fn(*mut *mut c_void, usize, usize) -> libc::c_int;
type MallocUsableSizeFn = unsafe extern "C" fn(*mut c_void) -> usize;
static REAL_MALLOC: AtomicUsize = AtomicUsize::new(0);
static REAL_FREE: AtomicUsize = AtomicUsize::new(0);
static REAL_REALLOC: AtomicUsize = AtomicUsize::new(0);
static REAL_CALLOC: AtomicUsize = AtomicUsize::new(0);
static REAL_POSIX_MEMALIGN: AtomicUsize = AtomicUsize::new(0);
static REAL_MALLOC_USABLE_SIZE: AtomicUsize = AtomicUsize::new(0);
pub unsafe fn resolve_real_functions() {
let rtld_next = -1isize as *mut c_void;
let m = libc::dlsym(rtld_next, c"malloc".as_ptr());
if !m.is_null() {
REAL_MALLOC.store(m as usize, Ordering::Release);
}
let f = libc::dlsym(rtld_next, c"free".as_ptr());
if !f.is_null() {
REAL_FREE.store(f as usize, Ordering::Release);
}
let r = libc::dlsym(rtld_next, c"realloc".as_ptr());
if !r.is_null() {
REAL_REALLOC.store(r as usize, Ordering::Release);
}
let c = libc::dlsym(rtld_next, c"calloc".as_ptr());
if !c.is_null() {
REAL_CALLOC.store(c as usize, Ordering::Release);
}
let pm = libc::dlsym(rtld_next, c"posix_memalign".as_ptr());
if !pm.is_null() {
REAL_POSIX_MEMALIGN.store(pm as usize, Ordering::Release);
}
let mu = libc::dlsym(rtld_next, c"malloc_usable_size".as_ptr());
if !mu.is_null() {
REAL_MALLOC_USABLE_SIZE.store(mu as usize, Ordering::Release);
}
}
#[cold]
#[inline(never)]
unsafe fn lazy_resolve(slot: &AtomicUsize, name: &core::ffi::CStr) -> usize {
let rtld_next = -1isize as *mut c_void; let ptr = libc::dlsym(rtld_next, name.as_ptr());
if ptr.is_null() {
return 0;
}
let val = ptr as usize;
let _ = slot.compare_exchange(0, val, Ordering::Release, Ordering::Acquire);
slot.load(Ordering::Acquire)
}
static BOOTSTRAP_BUF_USED: AtomicUsize = AtomicUsize::new(0);
const BOOTSTRAP_BUF_SIZE: usize = 65536;
static mut BOOTSTRAP_BUF: [u8; BOOTSTRAP_BUF_SIZE] = [0u8; BOOTSTRAP_BUF_SIZE];
unsafe fn bootstrap_malloc(size: usize) -> *mut u8 {
let aligned_size = (size + 15) & !15;
loop {
let offset = BOOTSTRAP_BUF_USED.load(Ordering::Relaxed);
if offset + aligned_size > BOOTSTRAP_BUF_SIZE {
return ptr::null_mut();
}
if BOOTSTRAP_BUF_USED
.compare_exchange_weak(
offset,
offset + aligned_size,
Ordering::Relaxed,
Ordering::Relaxed,
)
.is_ok()
{
return core::ptr::addr_of_mut!(BOOTSTRAP_BUF)
.cast::<u8>()
.add(offset);
}
}
}
unsafe fn bootstrap_memalign(alignment: usize, size: usize) -> *mut u8 {
let extra = alignment - 1;
let total = match size.checked_add(extra) {
Some(t) => t,
None => return ptr::null_mut(),
};
let aligned_total = (total + 15) & !15;
loop {
let offset = BOOTSTRAP_BUF_USED.load(Ordering::Relaxed);
if offset + aligned_total > BOOTSTRAP_BUF_SIZE {
return ptr::null_mut();
}
if BOOTSTRAP_BUF_USED
.compare_exchange_weak(
offset,
offset + aligned_total,
Ordering::Relaxed,
Ordering::Relaxed,
)
.is_ok()
{
let base = core::ptr::addr_of_mut!(BOOTSTRAP_BUF)
.cast::<u8>()
.add(offset);
let aligned = ((base as usize + alignment - 1) & !(alignment - 1)) as *mut u8;
return aligned;
}
}
}
unsafe fn is_bootstrap_ptr(ptr: *mut u8) -> bool {
let base = core::ptr::addr_of!(BOOTSTRAP_BUF) as usize;
let p = ptr as usize;
(base..base + BOOTSTRAP_BUF_SIZE).contains(&p)
}
#[inline]
pub unsafe fn malloc(size: usize) -> *mut u8 {
let mut f = REAL_MALLOC.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_MALLOC, c"malloc");
}
if f != 0 {
let func: MallocFn = core::mem::transmute(f);
func(size) as *mut u8
} else {
bootstrap_malloc(size)
}
}
#[inline]
pub unsafe fn free(ptr: *mut u8) {
if ptr.is_null() || is_bootstrap_ptr(ptr) {
return;
}
let mut f = REAL_FREE.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_FREE, c"free");
}
if f != 0 {
let func: FreeFn = core::mem::transmute(f);
func(ptr as *mut c_void);
}
}
#[inline]
pub unsafe fn realloc(ptr: *mut u8, size: usize) -> *mut u8 {
if ptr.is_null() {
return malloc(size);
}
if is_bootstrap_ptr(ptr) {
let new = malloc(size);
if !new.is_null() {
let base = core::ptr::addr_of!(BOOTSTRAP_BUF) as usize;
let old_offset = ptr as usize - base;
let max_old_size = BOOTSTRAP_BUF_SIZE - old_offset;
let copy_size = size.min(max_old_size);
ptr::copy_nonoverlapping(ptr, new, copy_size);
}
return new;
}
let mut f = REAL_REALLOC.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_REALLOC, c"realloc");
}
if f != 0 {
let func: ReallocFn = core::mem::transmute(f);
func(ptr as *mut c_void, size) as *mut u8
} else {
ptr::null_mut()
}
}
#[inline]
pub unsafe fn calloc(nmemb: usize, size: usize) -> *mut u8 {
let mut f = REAL_CALLOC.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_CALLOC, c"calloc");
}
if f != 0 {
let func: CallocFn = core::mem::transmute(f);
func(nmemb, size) as *mut u8
} else {
let total = match nmemb.checked_mul(size) {
Some(t) => t,
None => return ptr::null_mut(),
};
let p = bootstrap_malloc(total);
if !p.is_null() {
ptr::write_bytes(p, 0, total);
}
p
}
}
#[inline]
pub unsafe fn memalign(alignment: usize, size: usize) -> *mut u8 {
let mut f = REAL_POSIX_MEMALIGN.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_POSIX_MEMALIGN, c"posix_memalign");
}
if f != 0 {
let func: PosixMemalignFn = core::mem::transmute(f);
let mut out: *mut c_void = ptr::null_mut();
let ret = func(&mut out, alignment, size);
if ret == 0 {
out as *mut u8
} else {
ptr::null_mut()
}
} else {
bootstrap_memalign(alignment, size)
}
}
#[inline]
pub unsafe fn malloc_usable_size(ptr: *mut u8) -> usize {
let mut f = REAL_MALLOC_USABLE_SIZE.load(Ordering::Acquire);
if f == 0 {
f = lazy_resolve(&REAL_MALLOC_USABLE_SIZE, c"malloc_usable_size");
}
if f != 0 {
let func: MallocUsableSizeFn = core::mem::transmute(f);
func(ptr as *mut c_void)
} else {
0
}
}