use std::collections::HashMap;
use std::ffi::c_void;
use std::ptr::NonNull;
use std::sync::Mutex;
use crate::Class;
struct AllocationInfo {
class: Class,
live: bool, }
lazy_static::lazy_static! {
static ref ALLOCATION_STATE_MAP: Mutex<HashMap<usize, AllocationInfo>> = Default::default();
}
pub fn can_be_allocated(class: Class, alloc: &NonNull<c_void>) -> Result<(), &'static str> {
let alignment = class.info().layout.align();
if (alloc.as_ptr() as usize % alignment) != 0 {
return Err("misaligned address");
}
let map = ALLOCATION_STATE_MAP.lock().unwrap();
if let Some(info) = map.get(&(alloc.as_ptr() as usize)) {
if info.class != class {
return Err("class mismatch");
}
if info.live {
return Err("double allocation");
}
}
Ok(())
}
pub fn mark_allocated(class: Class, alloc: &NonNull<c_void>) -> Result<(), &'static str> {
let info = class.info();
let alignment = info.layout.align();
if (alloc.as_ptr() as usize % alignment) != 0 {
return Err("misaligned address");
}
if info.zero_init {
let ptr = alloc.as_ptr() as *const u8;
for i in 0..info.layout.size() {
if unsafe { std::ptr::read(ptr.add(i)) } != 0 {
return Err("non zero-filled allocation");
}
}
}
let mut map = ALLOCATION_STATE_MAP.lock().unwrap();
let mut info = map
.entry(alloc.as_ptr() as usize)
.or_insert(AllocationInfo { class, live: false });
if info.class != class {
return Err("class mismatch");
}
if info.live {
return Err("double allocation");
}
info.live = true;
Ok(())
}
pub fn mark_released(class: Class, alloc: &NonNull<c_void>) -> Result<(), &'static str> {
let mut map = ALLOCATION_STATE_MAP.lock().unwrap();
let mut info = map
.get_mut(&(alloc.as_ptr() as usize))
.ok_or("Released unknown address")?;
if info.class != class {
return Err("class mismatch");
}
if !info.live {
return Err("double free");
}
info.live = false;
Ok(())
}
pub fn has_been_released(class: Class, alloc: &NonNull<c_void>) -> Result<(), &'static str> {
let map = ALLOCATION_STATE_MAP.lock().unwrap();
let info = map
.get(&(alloc.as_ptr() as usize))
.ok_or("Released unknown address")?;
if info.class != class {
return Err("class mismatch");
}
if info.live {
return Err("released a live allocation");
}
Ok(())
}