pub struct DebugCheckingAllocator<A>where
A: BStackAllocator<Error = Error>,{ /* private fields */ }Expand description
Debug-only allocator wrapper that validates allocations and deallocations.
Wraps any allocator whose Allocated type is BStackOwnedSlice and whose
Error is io::Error. Maintains in-memory sets of allocated and freed
regions and validates every operation against them.
§Panics
Panics if:
- A newly allocated region overlaps with an existing allocated region
- A reallocated region overlaps with an existing allocated region
- A region being freed overlaps with a previously freed region
These panics indicate bugs in the underlying allocator implementation or a double free in the calling code.
§Thread Safety
The internal tracking sets are protected by a Mutex for internal bookkeeping, but
allocation operations and tracking updates must not be assumed to be an atomic,
cross-thread synchronization boundary. Concurrent use of this debug wrapper is therefore
not supported unless the caller provides external synchronization.
Implementations§
Source§impl<A> DebugCheckingAllocator<A>where
A: BStackAllocator<Error = Error>,
impl<A> DebugCheckingAllocator<A>where
A: BStackAllocator<Error = Error>,
Sourcepub fn new(inner: A) -> Self
pub fn new(inner: A) -> Self
Create a new DebugCheckingAllocator wrapping inner.
The allocator starts with empty tracking sets. If you’re reopening
a file from a previous session and want to pre-populate those sets,
use Self::with_state instead.
Sourcepub fn with_state(
inner: A,
allocated: impl IntoIterator<Item = Range<u64>>,
freed: impl IntoIterator<Item = Range<u64>>,
) -> Self
pub fn with_state( inner: A, allocated: impl IntoIterator<Item = Range<u64>>, freed: impl IntoIterator<Item = Range<u64>>, ) -> Self
Create a new DebugCheckingAllocator wrapping inner, with pre-populated tracking sets.
Use this when reopening a file from a previous session and you have metadata to reconstruct which regions were allocated or freed.
§Panics
Panics if the initial state is inconsistent:
- Any two ranges within
allocatedoverlap - Any two ranges within
freedoverlap - Any range in
allocatedoverlaps with any range infreed
Sourcepub fn into_inner(self) -> A
pub fn into_inner(self) -> A
Consume this allocator and return the inner allocator.
Trait Implementations§
Source§impl<A> BStackAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
impl<A> BStackAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
Source§type Allocated<'a> = BStackOwnedSlice<'a, DebugCheckingAllocator<A>>
where
Self: 'a
type Allocated<'a> = BStackOwnedSlice<'a, DebugCheckingAllocator<A>> where Self: 'a
Source§fn into_stack(self) -> BStack ⓘ
fn into_stack(self) -> BStack ⓘ
Source§fn alloc(&self, len: u64) -> Result<Self::Allocated<'_>>
fn alloc(&self, len: u64) -> Result<Self::Allocated<'_>>
len zero-initialised bytes. Read moreSource§fn realloc<'a>(
&'a self,
handle: BStackOwnedSlice<'a, Self>,
new_len: u64,
) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
fn realloc<'a>( &'a self, handle: BStackOwnedSlice<'a, Self>, new_len: u64, ) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
Source§fn dealloc<'a>(
&'a self,
handle: BStackOwnedSlice<'a, Self>,
) -> Result<(), BStackAllocError<'a, Self>>
fn dealloc<'a>( &'a self, handle: BStackOwnedSlice<'a, Self>, ) -> Result<(), BStackAllocError<'a, Self>>
handle. Read moreSource§impl<A> BStackBulkAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackBulkAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
impl<A> BStackBulkAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackBulkAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
Source§fn alloc_bulk(
&self,
lengths: impl AsRef<[u64]>,
) -> Result<Vec<Self::Allocated<'_>>>
fn alloc_bulk( &self, lengths: impl AsRef<[u64]>, ) -> Result<Vec<Self::Allocated<'_>>>
Source§fn dealloc_bulk<'a>(
&'a self,
handles: impl IntoIterator<Item = BStackOwnedSlice<'a, Self>>,
) -> Result<(), BStackBulkAllocError<'a, Self>>
fn dealloc_bulk<'a>( &'a self, handles: impl IntoIterator<Item = BStackOwnedSlice<'a, Self>>, ) -> Result<(), BStackBulkAllocError<'a, Self>>
Source§impl<A> BStackInPlaceResizeAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackInPlaceResizeAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
Forwards to the inner allocator’s front/back in-place resize, with the
same overlap checking as realloc.
impl<A> BStackInPlaceResizeAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackInPlaceResizeAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
Forwards to the inner allocator’s front/back in-place resize, with the
same overlap checking as realloc.
Only available when the wrapped allocator implements
BStackInPlaceResizeAllocator itself, for the same reason as
BStackUninitAllocator above: the wrapper never fabricates a structural
guarantee the inner allocator does not make.
A nonzero prepend moves the region’s start, so unlike
realloc the tracked region cannot simply be
resized in place: the old (start, len) is retired into the freed set and
(start - prepend, len + prepend + append) is recorded as newly allocated,
exactly as a relocating realloc would be tracked. A debug assertion checks
the trait’s exact-position guarantee on every success. An Unsupported
failure is a clean pre-mutation rejection — the inner handle comes back
untouched and tracking is left exactly as it was.
Source§fn realloc_inplace<'a>(
&'a self,
handle: BStackOwnedSlice<'a, Self>,
prepend: i64,
append: i64,
) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
fn realloc_inplace<'a>( &'a self, handle: BStackOwnedSlice<'a, Self>, prepend: i64, append: i64, ) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
handle in place by prepend bytes at the front and append
bytes at the back in one call. Read moreSource§impl<A> BStackUninitAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackUninitAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
impl<A> BStackUninitAllocator for DebugCheckingAllocator<A>where
for<'b> A: 'static + BStackUninitAllocator<Error = Error> + BStackAllocator<Allocated<'b> = BStackOwnedSlice<'b, A>>,
Only available when the wrapped allocator implements
BStackUninitAllocator itself — the wrapper never fabricates the trait for
an allocator that has no cheaper uninitialised path, so
DebugCheckingAllocator<A>: BStackUninitAllocator is exactly as truthful a
signal as A: BStackUninitAllocator.
The overlap, double-free and partial-free checks are unaffected: they are driven by allocation coordinates, which the uninitialised path produces exactly as the initialised one does. The wrapper does not (and cannot) verify region contents, so it makes no assertion about whether returned bytes are zero.
Source§fn alloc_uninit(&self, len: u64) -> Result<Self::Allocated<'_>>
fn alloc_uninit(&self, len: u64) -> Result<Self::Allocated<'_>>
len bytes without zero-initialising them. Read moreSource§fn realloc_uninit<'a>(
&'a self,
handle: BStackOwnedSlice<'a, Self>,
new_len: u64,
) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
fn realloc_uninit<'a>( &'a self, handle: BStackOwnedSlice<'a, Self>, new_len: u64, ) -> Result<BStackOwnedSlice<'a, Self>, BStackAllocError<'a, Self>>
handle to new_len bytes without
zero-initialising any newly added bytes. Read more