Heap safe destructor
This commit is contained in:
parent
5de72012bf
commit
6691847830
@ -2,9 +2,10 @@ use crate::errors::throw_from_windows_err_code;
|
|||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::pin::Pin;
|
use std::pin::Pin;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
|
use std::thread::panicking;
|
||||||
use windows::Win32::Foundation::{GetLastError, HANDLE};
|
use windows::Win32::Foundation::{GetLastError, HANDLE};
|
||||||
use windows::Win32::System::Memory::{
|
use windows::Win32::System::Memory::{
|
||||||
HeapAlloc, HeapCreate, HeapFree, HEAP_FLAGS, HEAP_NO_SERIALIZE,
|
HEAP_FLAGS, HEAP_NO_SERIALIZE, HeapAlloc, HeapCreate, HeapDestroy, HeapFree,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) struct Allocator {
|
pub(crate) struct Allocator {
|
||||||
@ -16,6 +17,7 @@ struct Header {
|
|||||||
prev: Option<NonNull<Header>>,
|
prev: Option<NonNull<Header>>,
|
||||||
next: Option<NonNull<Header>>,
|
next: Option<NonNull<Header>>,
|
||||||
destructor: unsafe fn(NonNull<c_void>),
|
destructor: unsafe fn(NonNull<c_void>),
|
||||||
|
value: NonNull<c_void>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Allocator {
|
impl Allocator {
|
||||||
@ -57,6 +59,14 @@ impl Allocator {
|
|||||||
)
|
)
|
||||||
.unwrap_or_else(|| throw_from_windows_err_code(GetLastError()));
|
.unwrap_or_else(|| throw_from_windows_err_code(GetLastError()));
|
||||||
|
|
||||||
|
h.as_mut().value = NonNull::new_unchecked(
|
||||||
|
h.as_ptr()
|
||||||
|
.map_addr(|a| a + Self::_calc_offset::<T>())
|
||||||
|
.cast::<c_void>(),
|
||||||
|
);
|
||||||
|
let mut p = Pin::new_unchecked(h.as_mut().value.cast::<T>().as_mut());
|
||||||
|
heap_free_on_exit::<false, _>(self.win_heap, h.cast(), || init(&mut p));
|
||||||
|
|
||||||
if let Some(mut last) = self.last {
|
if let Some(mut last) = self.last {
|
||||||
last.as_mut().next = Some(h);
|
last.as_mut().next = Some(h);
|
||||||
}
|
}
|
||||||
@ -65,15 +75,6 @@ impl Allocator {
|
|||||||
h.as_mut().destructor = Self::_destructor::<T>;
|
h.as_mut().destructor = Self::_destructor::<T>;
|
||||||
self.last = Some(h);
|
self.last = Some(h);
|
||||||
|
|
||||||
let mut p = Pin::new_unchecked(
|
|
||||||
&mut *(h
|
|
||||||
.as_ptr()
|
|
||||||
.map_addr(|a| a + Self::_calc_offset::<T>())
|
|
||||||
.cast::<T>()),
|
|
||||||
);
|
|
||||||
|
|
||||||
init(&mut p);
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,16 +96,82 @@ impl Allocator {
|
|||||||
if self.last == Some(NonNull::from_mut(h)) {
|
if self.last == Some(NonNull::from_mut(h)) {
|
||||||
self.last = h.prev;
|
self.last = h.prev;
|
||||||
}
|
}
|
||||||
|
heap_free_on_exit::<true, _>(self.win_heap, NonNull::from_mut(h).cast(), || {
|
||||||
|
(h.destructor)(p.cast::<c_void>())
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
(h.destructor)(p.cast::<c_void>());
|
fn heap_free_on_exit<const FreeOnSuccess: bool, R>(
|
||||||
|
win_heap: HANDLE,
|
||||||
|
ptr: NonNull<c_void>,
|
||||||
|
scope: impl FnOnce() -> R,
|
||||||
|
) -> R {
|
||||||
|
let defer = HeapFreeOnDrop::<FreeOnSuccess> { win_heap, ptr };
|
||||||
|
let ret = scope();
|
||||||
|
drop(defer);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct HeapFreeOnDrop<const FreeOnSuccess: bool> {
|
||||||
|
win_heap: HANDLE,
|
||||||
|
ptr: NonNull<c_void>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<const FreeOnSuccess: bool> Drop for HeapFreeOnDrop<FreeOnSuccess> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
if !panicking() && !FreeOnSuccess {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
unsafe {
|
||||||
match HeapFree(
|
match HeapFree(
|
||||||
self.win_heap,
|
self.win_heap,
|
||||||
HEAP_FLAGS::default(),
|
HEAP_FLAGS::default(),
|
||||||
Some((h as *mut Header).cast()),
|
Some(self.ptr.cast().as_mut()),
|
||||||
) {
|
) {
|
||||||
Ok(_) => return,
|
Ok(_) => return,
|
||||||
Err(err) => throw_from_windows_err_code(err.code())
|
Err(err) => throw_from_windows_err_code(err.code()),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for Allocator {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
drop(RecursiveHeapDestructor {
|
||||||
|
win_heap: self.win_heap,
|
||||||
|
next: self.last,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct RecursiveHeapDestructor {
|
||||||
|
win_heap: HANDLE,
|
||||||
|
next: Option<NonNull<Header>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for RecursiveHeapDestructor {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
match self.next {
|
||||||
|
Some(mut h) => {
|
||||||
|
let h = h.as_mut();
|
||||||
|
let next_destructor = RecursiveHeapDestructor {
|
||||||
|
win_heap: self.win_heap,
|
||||||
|
next: h.prev,
|
||||||
|
};
|
||||||
|
heap_free_on_exit::<true, _>(
|
||||||
|
self.win_heap,
|
||||||
|
NonNull::from_mut(h).cast(),
|
||||||
|
|| (h.destructor)(h.value),
|
||||||
|
);
|
||||||
|
drop(next_destructor);
|
||||||
|
}
|
||||||
|
None => match HeapDestroy(self.win_heap) {
|
||||||
|
Ok(()) => return,
|
||||||
|
Err(err) => throw_from_windows_err_code(err.code()),
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user