pub struct NtAlloc<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32 = DEFAULT_MEMORY_TAG, const TAGGED_DEALLOC: bool = true, const REALIGN: bool = true>;Expand description
A stateless, #![no_std]-friendly Windows kernel pool allocator.
NtAlloc is a zero-sized type: all of its behavior is selected entirely at
compile time via its const generic parameters, and every operation is
exposed as an associated function, so no instance ever needs to be
constructed to use them directly. An instance is still needed to satisfy
the GlobalAlloc trait bound (and, with the allocator-api feature,
the Allocator one), and can always be created with
Default::default() at zero runtime cost.
§Type Parameters
ALLOC_POOL_FLAGS: the pool flags passed toExAllocatePool2.POOL_FLAG_PAGEDorPOOL_FLAG_NON_PAGEDselects the pool, andPOOL_FLAG_UNINITIALIZED,POOL_FLAG_CACHE_ALIGNED,POOL_FLAG_USE_QUOTAorPOOL_FLAG_SPECIAL_POOLcan be added to it, as in the example below. Flags fromwdm.hthat this crate does not export can be passed as raw values.POOL_FLAG_RAISE_ON_FAILUREis refused; see below.MEMORY_TAG: the 4-byte pool tag attached to every allocation, used by tools such as!poolused/!poolfindto attribute pool memory back to this allocator. Defaults toDEFAULT_MEMORY_TAG. It must be one to four printable ASCII characters (0x20to0x7E), padded with zero bytes at the end when shorter, with at least one letter or digit; see below.TAGGED_DEALLOC: selects the free routine used byNtAlloc::deallocate:trueusesExFreePoolWithTag(the tag must match the one the memory was allocated with),falseuses the untaggedExFreePool. Defaults totrue.REALIGN: whetherNtAlloc::allocate_aligned, and through it theGlobalAllocandAllocatorimplementations, serve aLayoutaligned more strictly than the pool guarantees for its size (seeNtAlloc::kernel_alignment) by over-allocating and realigning, as the crate documentation describes. Defaults totrue;falseturns realignment off, as described below.
Prefer the PagedAlloc/NonPagedAlloc aliases over naming NtAlloc
directly, unless the configuration needs more flags than the pool:
use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED, POOL_FLAG_UNINITIALIZED};
// Non-paged pool that skips the zeroing ExAllocatePool2 otherwise does.
type ScratchAlloc = NtAlloc<{ POOL_FLAG_NON_PAGED | POOL_FLAG_UNINITIALIZED }>;
assert!(!ScratchAlloc::POOL_ZEROES);Call associated functions through an alias that names the whole type, such
as type Alloc = NonPagedAlloc; followed by Alloc::allocate(64). Writing
NonPagedAlloc::allocate(64) does not compile (E0284): Rust fills in the
aliases’ default parameters only where a type is expected.
§Turning realignment off
Realignment is on by default. A driver that never needs more than the
pool’s own alignment can turn it off by setting REALIGN to false:
NtAlloc::allocate_aligned, and with it the GlobalAlloc and
Allocator implementations, then pass every request to the pool by size
and ignore the alignment it asks for. Nothing is over-allocated or stored
next to a block, and a block is aligned only as the pool aligns it: to
MIN_ALIGNMENT below a page, and to a page from one page up.
Only do so if nothing allocated through such a configuration needs more,
including types from other crates, which a #[global_allocator] serves
too. Anything #[repr(align(32))] or larger needs more, as do 256- and
512-bit SIMD vectors and cache-padded wrappers such as crossbeam’s
CachePadded. A misaligned Box or reference is undefined behaviour, and
an aligned SIMD load from one faults, which in a driver is a bug check.
Debug builds usually stop at the first misaligned access, with “misaligned
pointer dereference”; release builds do not.
use core::alloc::{GlobalAlloc, Layout};
use ntalloc::{DEFAULT_MEMORY_TAG, MIN_ALIGNMENT, NonPagedAlloc};
type NoRealignAlloc = NonPagedAlloc<DEFAULT_MEMORY_TAG, true, false>;
let alloc = NoRealignAlloc::default();
// Asks for 64-byte alignment, but gets only what the pool gives a small block.
let layout = Layout::from_size_align(64, 64).unwrap();
// SAFETY: the layout has a non-zero size.
let ptr = unsafe { alloc.alloc(layout) };
assert!(!ptr.is_null());
assert_eq!(ptr as usize % MIN_ALIGNMENT, 0);
// SAFETY: from `alloc` with this layout, freed once.
unsafe { alloc.dealloc(ptr, layout) };§Unsupported configurations
These configurations break ExAllocatePool2’s documented rules, fail every
allocation, are listed by Microsoft as bug checks, or fail in a way Rust
cannot handle, so a type that uses one fails to build as soon as anything
allocates with it. The error comes from cargo build; cargo check does
not evaluate it.
POOL_FLAG_RAISE_ON_FAILURE(0x20) makesExAllocatePool2raise an SEH exception on failure instead of returning null. Rust cannot catch SEH: left unhandled the exception bugchecks the system, and handled further up it unwinds through Rust frames, which is undefined behaviour.- A zero
MEMORY_TAG, whichExAllocatePool2rejects as invalid. - A
MEMORY_TAGthat is not one to four printable ASCII characters (0x20to0x7E) followed only by zero padding, asExAllocatePool2’s documentation requires: one with a control byte, a byte above0x7E, or a zero byte before its last character. - A
MEMORY_TAGwith no ASCII letter or digit, such as four spaces, which Microsoft lists as bug checkBAD_POOL_CALLER(0x9D). "BIG ", a tag the kernel reserves, which Microsoft lists as bug checkBAD_POOL_CALLER(0x9C).
Without POOL_FLAG_RAISE_ON_FAILURE, failure is reported as null.
Fallible APIs such as Box::try_new_in return it as an error, and
infallible ones such as Box::new pass it to handle_alloc_error, which
in a #![no_std] build panics by default: the fail-fast behaviour the flag
would otherwise give.
The flags are not validated beyond that: any other combination the pool considers invalid fails at run time, like any other allocation failure.
use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED};
// 0x20 is POOL_FLAG_RAISE_ON_FAILURE, which this crate does not export.
type Raising = NtAlloc<{ POOL_FLAG_NON_PAGED | 0x20 }>;
let _ = Raising::allocate(64);use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED};
type Untagged = NtAlloc<POOL_FLAG_NON_PAGED, 0>;
let _ = Untagged::allocate(64);use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED};
// A zero byte before the last character.
type Gapped = NtAlloc<POOL_FLAG_NON_PAGED, { u32::from_ne_bytes(*b"ab\0c") }>;
let _ = Gapped::allocate(64);use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED};
type Blank = NtAlloc<POOL_FLAG_NON_PAGED, { u32::from_ne_bytes(*b" ") }>;
let _ = Blank::allocate(64);use ntalloc::{NtAlloc, POOL_FLAG_NON_PAGED};
type Big = NtAlloc<POOL_FLAG_NON_PAGED, { u32::from_ne_bytes(*b"BIG ") }>;
let _ = Big::allocate(64);Implementations§
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Sourcepub const POOL_ZEROES: bool
pub const POOL_ZEROES: bool
Whether allocations from this configuration arrive zero-initialized.
ExAllocatePool2 zeroes every block it returns unless
POOL_FLAG_UNINITIALIZED is among ALLOC_POOL_FLAGS, so this is a
property of the type, resolved at compile time. It is true for
PagedAlloc and NonPagedAlloc.
GlobalAlloc::alloc_zeroed, and with the allocator-api feature
Allocator::allocate_zeroed, consult it to skip the redundant second
pass their default implementations would otherwise make over memory the
pool has already zeroed.
Sourcepub fn kernel_alignment(size: usize) -> usize
pub fn kernel_alignment(size: usize) -> usize
Returns the alignment guarantee ExAllocatePool2 provides for an
allocation of size bytes.
Per the ExAllocatePool2 documentation, allocations of at
least one page are page-aligned; smaller allocations are only
guaranteed MIN_ALIGNMENT.
§Parameters
size: the requested allocation size, in bytes.
§Returns
PAGE_SIZE if size is at least one page, otherwise MIN_ALIGNMENT.
§Examples
use ntalloc::{PagedAlloc, MIN_ALIGNMENT};
use windows_sys::Wdk::System::SystemServices::PAGE_SIZE;
type Alloc = PagedAlloc;
assert_eq!(Alloc::kernel_alignment(16), MIN_ALIGNMENT);
assert_eq!(Alloc::kernel_alignment(PAGE_SIZE as usize), PAGE_SIZE as usize);Sourcepub fn kernel_allocate(size: usize) -> *mut u8
pub fn kernel_allocate(size: usize) -> *mut u8
Allocates size bytes directly from the kernel pool via
ExAllocatePool2, bypassing the process-heap backend that
NtAlloc::allocate uses in tests and under the usermode-backend
feature. It always reaches the pool, so outside a kernel it can only
be called with a size of 0.
§Parameters
size: the number of bytes to allocate. A zero-size request never reaches the pool:ExAllocatePool2documentsNumberOfBytesas “a non-zero number of bytes”, and lists only memory exhaustion and a bad tag or flags as reasons it returns null — so it defines no behaviour at all for0. This returns null instead.
§Returns
A pointer to the allocated memory, or a null pointer if size is 0
or the allocation fails.
§Examples
use ntalloc::NonPagedAlloc;
type Alloc = NonPagedAlloc;
let ptr = Alloc::kernel_allocate(64);
assert!(!ptr.is_null());Sourcepub fn allocate(size: usize) -> *mut u8
pub fn allocate(size: usize) -> *mut u8
Allocates size bytes, returning a null pointer for a zero-size
request.
With the usermode-backend feature, and in this crate’s own tests,
allocation is redirected to the process heap so that the allocator’s
logic can run without a kernel; otherwise this calls
NtAlloc::kernel_allocate.
The zero-size check lives in each backend rather than here, so the shipped path performs it once instead of twice.
§Parameters
size: the number of bytes to allocate.
§Returns
A pointer to the allocated memory, or a null pointer if size is 0
or the allocation fails.
§Examples
use ntalloc::NonPagedAlloc;
type Alloc = NonPagedAlloc;
let ptr = Alloc::allocate(64);
assert!(!ptr.is_null());
// SAFETY: `ptr` came from `Alloc::allocate` and needed no realignment.
unsafe { Alloc::deallocate(ptr) };Sourcepub fn allocate_aligned(layout: Layout) -> *mut u8
pub fn allocate_aligned(layout: Layout) -> *mut u8
Allocates memory for layout, handling alignment requirements stronger
than what the kernel pool allocator natively provides.
If layout.align() is no stronger than NtAlloc::kernel_alignment
for the requested size, this simply forwards to NtAlloc::allocate.
Otherwise it over-allocates by layout.align() extra bytes, rounds the
result up to layout.align(), and stashes the original pointer just
before the returned one (see the crate-level documentation for
details). With REALIGN set to false it forwards every request to
NtAlloc::allocate instead: see
Turning realignment off.
§Parameters
layout: the size and alignment to allocate for.
§Returns
A pointer to layout.size() bytes aligned to layout.align() (only to
the pool’s own alignment when REALIGN is false), or a null pointer
on allocation failure.
A zero-size layout always returns a null pointer, and never reaches
the pool. GlobalAlloc calls a zero-size request undefined
behaviour but invites implementations to “guarantee a sentinel address
or a null pointer in response to a zero-size allocation request” —
this is that guarantee. Callers needing a usable pointer for an empty
allocation want the Allocator impl (the allocator-api feature),
which returns a dangling one as that trait requires.
§Note
A pointer returned from this function when realignment was required
cannot be freed with the plain NtAlloc::deallocate — that function
has no way to recover the original pointer. Free it with
NtAlloc::deallocate_aligned, passing the same layout, or through
this type’s GlobalAlloc/Allocator implementations, which do
the same thing. (For a pointer that did not need realignment,
NtAlloc::deallocate is fine either way — but since only layout
distinguishes the two cases, always pairing with
NtAlloc::deallocate_aligned is the rule that cannot go wrong.)
§Examples
use core::alloc::Layout;
use ntalloc::NonPagedAlloc;
type Alloc = NonPagedAlloc;
let layout = Layout::from_size_align(16, 64).unwrap();
let ptr = Alloc::allocate_aligned(layout);
assert!(!ptr.is_null());
assert_eq!(ptr as usize % layout.align(), 0);
// SAFETY: `ptr` came from `allocate_aligned` with this exact layout.
unsafe { Alloc::deallocate_aligned(ptr, layout) };Sourcepub unsafe fn deallocate(ptr: *mut u8)
pub unsafe fn deallocate(ptr: *mut u8)
Frees a pointer previously returned by NtAlloc::allocate. Normally
that is a pool block, which NtAlloc::kernel_allocate returns too,
freed with the routine TAGGED_DEALLOC selects. Under the
usermode-backend feature both functions use the process heap instead.
This does not account for the pointer-stashing done by
NtAlloc::allocate_aligned for over-aligned requests — see that
function’s documentation for when it is safe to call this directly.
§Safety
The caller must guarantee all of the following:
ptris non-null. UnlikeNtAlloc::deallocate_aligned, this function does not check, andExFreePool/ExFreePoolWithTagbugchecks on a null pointer rather than ignoring it the way C’sfreewould.ptrcame from the sameNtAllocconfiguration: the same pool flags, the sameMEMORY_TAG, and the sameTAGGED_DEALLOC. Freeing with a mismatched tag corrupts the pool.ptris the address the pool returned, not one thatNtAlloc::allocate_alignedadjusted for over-alignment. Those go toNtAlloc::deallocate_alignedinstead.ptrhas not already been freed, and is not used afterwards.
§Examples
use ntalloc::NonPagedAlloc;
type Alloc = NonPagedAlloc;
let ptr = Alloc::allocate(64);
assert!(!ptr.is_null());
// SAFETY: `ptr` came from `Alloc::allocate` and needed no realignment.
unsafe { Alloc::deallocate(ptr) };Sourcepub unsafe fn deallocate_aligned(ptr: *mut u8, layout: Layout)
pub unsafe fn deallocate_aligned(ptr: *mut u8, layout: Layout)
Frees a pointer returned by NtAlloc::allocate_aligned for layout,
recovering and freeing the original (pre-realignment) pointer when
layout’s alignment required over-allocation.
This is the counterpart to NtAlloc::allocate_aligned: a pointer
from that function must be freed through this one, because for an
over-aligned request the address handed out is not the address the
pool returned, and only this function knows how to recover it.
Passing a null ptr is a no-op.
§Safety
The caller must guarantee all of the following:
ptrwas returned byNtAlloc::allocate_alignedon this sameNtAllocinstantiation — the same pool flags, the sameMEMORY_TAG, the sameTAGGED_DEALLOCand the sameREALIGN— or is null.layoutis the exactLayoutthat was passed to that call.layoutalone decides whether the original pointer is read back from the slot beforeptrorptris freed directly, so a mismatched layout will either handExFreePoolan interior pointer or readPOINTER_SIZEbytes of unrelated memory and free whatever they happen to contain.ptrhas not already been freed, and is not used afterwards.
None of these can be checked at runtime: an interior pointer and a valid one are indistinguishable, and the pool allocator has no way to report that a tag or a size did not match.
Trait Implementations§
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Allocator for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Available on crate feature allocator-api only.
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Allocator for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
allocator-api only.Source§fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
Allocates memory for layout via NtAlloc::allocate_aligned,
returning it as a NonNull<[u8]> slice.
§Returns
Ok(_)— aNonNull<[u8]>slice of exactlylayout.size()bytes (never more, even though the real underlying allocation may be larger than that once realignment padding is accounted for).Ok(_)— for a zero-sizelayout, a dangling pointer aligned tolayout.align()with a length of0.Allocatorrequires zero-sized allocations to succeed, unlikeGlobalAlloc, and the pool is never involved. Passing it back toAllocator::deallocateis correct and does nothing.Err(AllocError)— only if the underlying pool allocation fails.
Source§fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
fn allocate_zeroed(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>
Allocates zero-initialized memory for layout.
Skips the second zeroing pass the default implementation would make
whenever NtAlloc::POOL_ZEROES holds, for the reasons given on
GlobalAlloc::alloc_zeroed. A zero-sized layout yields the same
dangling, length-0 slice Allocator::allocate returns, which is
trivially zeroed.
Source§unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
unsafe fn deallocate(&self, ptr: NonNull<u8>, layout: Layout)
Frees a pointer previously returned by Allocator::allocate (or
grow/shrink) on this same allocator.
§Safety
ptr must denote memory currently allocated via this allocator, and
layout must be the same layout that was used to allocate it, per
the Allocator::deallocate contract.
1.100.0 (const: unstable) · Source§unsafe fn grow(
&self,
ptr: NonNull<u8>,
old_layout: Layout,
new_layout: Layout,
) -> Result<NonNull<[u8]>, AllocError>
unsafe fn grow( &self, ptr: NonNull<u8>, old_layout: Layout, new_layout: Layout, ) -> Result<NonNull<[u8]>, AllocError>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> AllocatorClone for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
allocator-api-markers only.Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Clone for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Clone for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Copy for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Debug for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Debug for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Default for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Default for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Eq for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> GlobalAlloc for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> GlobalAlloc for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§unsafe fn alloc(&self, layout: Layout) -> *mut u8
unsafe fn alloc(&self, layout: Layout) -> *mut u8
Allocates memory for layout via NtAlloc::allocate_aligned.
§Safety
As GlobalAlloc::alloc requires: layout must have non-zero size,
and the caller must pass the exact same layout to
GlobalAlloc::dealloc (or realloc) when freeing the returned
pointer.
Should a zero-size layout arrive anyway, this returns null rather
than reaching ExAllocatePool2, which documents no behaviour for a
zero-size request. See NtAlloc::allocate_aligned.
Source§unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout)
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout)
Frees a pointer previously returned by GlobalAlloc::alloc (or
realloc) on this same allocator, correctly recovering any pointer
adjustment NtAlloc::allocate_aligned made for over-aligned
requests.
§Safety
ptr must have been returned by a prior call to GlobalAlloc::alloc
(or realloc) on this same NtAlloc instantiation, and layout must
be the exact layout used for that allocation.
Source§unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8
Allocates zero-initialized memory for layout.
The default implementation of this method allocates and then writes
zeroes over the whole block. ExAllocatePool2 has already done that,
so when NtAlloc::POOL_ZEROES holds this simply returns the
allocation and the second pass is skipped — the condition is a const,
so only one branch survives compilation.
For a realigned request the returned region still arrives zeroed: it
lies inside the larger block the pool zeroed, and the pointer
NtAlloc::allocate_aligned stashes goes in the bytes before it.
§Safety
As GlobalAlloc::alloc: layout must have non-zero size, and the
same layout must come back on the free path.
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Hash for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Hash for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Ord for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> Ord for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
1.21.0 (const: unstable) · Source§fn max(self, other: Self) -> Selfwhere
Self: Sized,
fn max(self, other: Self) -> Selfwhere
Self: Sized,
1.21.0 (const: unstable) · Source§fn min(self, other: Self) -> Selfwhere
Self: Sized,
fn min(self, other: Self) -> Selfwhere
Self: Sized,
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> PartialEq for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> PartialEq for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
Source§impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> PartialOrd for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> PartialOrd for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
impl<const ALLOC_POOL_FLAGS: POOL_FLAGS, const MEMORY_TAG: u32, const TAGGED_DEALLOC: bool, const REALIGN: bool> StaticAllocator for NtAlloc<ALLOC_POOL_FLAGS, MEMORY_TAG, TAGGED_DEALLOC, REALIGN>
allocator-api-markers only.