use std::alloc::{GlobalAlloc, Layout, System};
use std::backtrace::Backtrace;
use std::sync::Arc;
use crate::{AllocZeroed, Event, Realloc, ReallocNull, Region, Request};
pub struct Allocator<T = System> {
delegate: T,
}
impl<T> Allocator<T> {
pub const fn new(delegate: T) -> Allocator<T> {
Allocator { delegate }
}
}
impl Allocator<System> {
pub const fn system() -> Allocator<System> {
Self::new(System)
}
}
unsafe impl<T> GlobalAlloc for Allocator<T>
where
T: GlobalAlloc,
{
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let ptr = self.delegate.alloc(layout);
if crate::is_muted() || ptr.is_null() {
if ptr.is_null() {
crate::with_state(move |s| {
s.borrow_mut().events.push(Event::AllocFailed);
});
}
return ptr;
}
crate::with_state(move |s| {
let region = Region {
ptr: ptr.into(),
size: layout.size(),
align: layout.align(),
};
let backtrace = crate::with_muted(|| Arc::new(Backtrace::capture()));
s.borrow_mut()
.events
.push(Event::Alloc(Request { region, backtrace }));
});
ptr
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
self.delegate.dealloc(ptr, layout);
if crate::is_muted() {
return;
}
crate::with_state(move |s| {
let backtrace = crate::with_muted(|| Arc::new(Backtrace::capture()));
s.borrow_mut().events.push(Event::Free(Request {
region: Region {
ptr: ptr.into(),
size: layout.size(),
align: layout.align(),
},
backtrace,
}));
});
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
let ptr = self.delegate.alloc_zeroed(layout);
if crate::is_muted() || ptr.is_null() {
if ptr.is_null() {
crate::with_state(move |s| {
s.borrow_mut().events.push(Event::AllocZeroedFailed);
});
}
return ptr;
}
crate::with_state(move |s| {
#[cfg(feature = "zeroed")]
let is_zeroed = Some(crate::utils::is_zeroed_ptr(ptr, layout.size()));
#[cfg(not(feature = "zeroed"))]
let is_zeroed = None;
let backtrace = crate::with_muted(|| Arc::new(Backtrace::capture()));
let request = Request {
region: Region {
ptr: ptr.into(),
size: layout.size(),
align: layout.align(),
},
backtrace,
};
s.borrow_mut()
.events
.push(Event::AllocZeroed(AllocZeroed { is_zeroed, request }));
});
ptr
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
if crate::is_muted() || ptr.is_null() {
if ptr.is_null() {
let backtrace = crate::with_muted(|| Arc::new(Backtrace::capture()));
crate::with_state(|s| {
s.borrow_mut()
.events
.push(Event::ReallocNull(ReallocNull { backtrace }));
});
}
return self.delegate.realloc(ptr, layout, new_size);
}
#[cfg(feature = "realloc")]
let min_size = usize::min(layout.size(), new_size);
#[cfg(feature = "realloc")]
let old_hash = crate::utils::hash_ptr(ptr, min_size);
let old_ptr = ptr.into();
let new_ptr = self.delegate.realloc(ptr, layout, new_size);
if new_ptr.is_null() {
crate::with_state(|s| {
s.borrow_mut().events.push(Event::ReallocFailed);
});
return new_ptr;
}
crate::with_state(move |s| {
#[cfg(feature = "realloc")]
let is_relocated = Some(old_hash == crate::utils::hash_ptr(new_ptr, min_size));
#[cfg(not(feature = "realloc"))]
let is_relocated = None;
let backtrace = crate::with_muted(|| Arc::new(Backtrace::capture()));
let free = Region {
ptr: old_ptr,
size: layout.size(),
align: layout.align(),
};
let alloc = Region {
ptr: new_ptr.into(),
size: new_size,
align: layout.align(),
};
s.borrow_mut().events.push(Event::Realloc(Realloc {
is_relocated,
free,
alloc,
backtrace,
}));
});
new_ptr
}
}