use core::{
alloc::{GlobalAlloc, Layout},
ffi::c_void,
ptr::{NonNull, null_mut},
};
use dinvk::{data::*, link};
static mut HEAP_HANDLE: Option<NonNull<c_void>> = None;
pub struct HypnusHeap;
impl HypnusHeap {
const HEAP_GROWABLE: u32 = 0x00000002;
fn create() -> HANDLE {
let handle = unsafe {
RtlCreateHeap(
Self::HEAP_GROWABLE,
null_mut(),
0,
0,
null_mut(),
null_mut()
)
};
let nonnull = unsafe { NonNull::new_unchecked(handle) };
unsafe { HEAP_HANDLE = Some(nonnull) };
handle
}
pub fn heap() -> HANDLE {
unsafe { HEAP_HANDLE.map(|p| p.as_ptr()).unwrap_or_else(Self::create) }
}
}
unsafe impl GlobalAlloc for HypnusHeap {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
let heap = Self::heap();
let size = layout.size();
if size == 0 {
return null_mut();
}
unsafe { RtlAllocateHeap(heap, 0, size) as *mut u8 }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
if ptr.is_null() {
return;
}
unsafe { core::ptr::write_bytes(ptr, 0, layout.size()) };
unsafe {
RtlFreeHeap(Self::heap(), 0, ptr.cast());
}
}
}
link!("ntdll" "system" fn RtlFreeHeap(heap: HANDLE, flags: u32, ptr: *mut c_void) -> i8);
link!("ntdll" "system" fn RtlAllocateHeap(heap: HANDLE, flags: u32, size: usize) -> *mut c_void);
link!("ntdll" "system" fn RtlCreateHeap(flags: u32, heap_base: *mut c_void, reserve_size: usize, commit_size: usize, lock: *mut c_void, parameters: *mut c_void) -> HANDLE);