use super::*;
use core::ptr::without_provenance_mut;
#[test]
fn require_realignment_test() {
let size = 16;
for shift in 0..=16u32 {
let alignment = 1usize << shift;
let layout = Layout::from_size_align(size, alignment).unwrap();
let already_satisfied = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::is_kernel_aligned(layout);
if alignment <= MIN_ALIGNMENT {
assert!(
already_satisfied,
"alignment {alignment} is within MIN_ALIGNMENT, so the pool \
should already satisfy it and no realignment is needed"
);
} else {
assert!(
!already_satisfied,
"alignment {alignment} exceeds what the pool guarantees for \
a {size}-byte request, so realignment is needed"
);
}
}
}
#[test]
fn original_pointer_location_test() {
let mut slots = [null_mut::<u8>(); 2];
let base = slots.as_mut_ptr();
let ptr = unsafe { base.add(1) }.cast::<u8>();
let original_ptr_location =
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::original_pointer_location(ptr);
assert_eq!(original_ptr_location, base);
}
#[test]
fn save_original_pointer_test() {
let mut slots = [null_mut::<u8>(); 2];
let aligned_ptr = unsafe { slots.as_mut_ptr().add(1) }.cast::<u8>();
let original_ptr = without_provenance_mut::<u8>(0x1000);
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::save_original_pointer(aligned_ptr, original_ptr);
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::original_pointer(aligned_ptr),
original_ptr
);
}
#[test]
fn align_up_to_test_less_than_min_alignment() {
let ptr = without_provenance_mut::<u8>(0x1003);
let alignment = 4;
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
ptr,
NonZeroUsize::new(alignment).unwrap(),
);
assert_eq!(aligned_ptr as usize % alignment, 0);
assert!(aligned_ptr as usize > ptr as usize);
}
#[test]
fn align_up_to_test_greater_than_min_alignment() {
let ptr = without_provenance_mut::<u8>(0x1003);
let alignment = 64;
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
ptr,
NonZeroUsize::new(alignment).unwrap(),
);
assert_eq!(aligned_ptr as usize % alignment, 0);
assert!(aligned_ptr as usize > ptr as usize);
}
#[test]
fn align_up_to_test_page_size_alignment() {
let ptr = without_provenance_mut::<u8>(0x1003);
let alignment = PAGE_SIZE as usize;
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
ptr,
NonZeroUsize::new(alignment).unwrap(),
);
assert_eq!(aligned_ptr as usize % alignment, 0);
assert!(aligned_ptr as usize > ptr as usize);
}
#[test]
fn align_up_to_test_greater_than_page_size_alignment() {
let ptr = without_provenance_mut::<u8>(0x1003);
let alignment = PAGE_SIZE as usize * 2;
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
ptr,
NonZeroUsize::new(alignment).unwrap(),
);
assert_eq!(aligned_ptr as usize % alignment, 0);
assert!(aligned_ptr as usize > ptr as usize);
}
#[test]
fn kernel_alignment_test() {
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_alignment(1),
MIN_ALIGNMENT
);
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_alignment(16),
MIN_ALIGNMENT
);
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_alignment(PAGE_SIZE as usize - 1),
MIN_ALIGNMENT
);
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_alignment(PAGE_SIZE as usize),
PAGE_SIZE as usize
);
assert_eq!(
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_alignment(PAGE_SIZE as usize + 1),
PAGE_SIZE as usize
);
}
#[test]
fn allocate_aligned_test_requires_realignment() {
let layout = Layout::from_size_align(16, 64).unwrap();
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(!aligned_ptr.is_null());
assert_eq!((aligned_ptr as usize) % layout.align(), 0);
let original_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::original_pointer(aligned_ptr);
assert!(!original_ptr.is_null());
assert!(original_ptr < aligned_ptr);
unsafe { PagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(aligned_ptr, layout) };
}
#[test]
fn allocate_aligned_test_no_realignment() {
let layout = Layout::from_size_align(16, 8).unwrap();
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(!aligned_ptr.is_null());
assert_eq!((aligned_ptr as usize) % layout.align(), 0);
unsafe { PagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(aligned_ptr, layout) };
}
#[test]
fn allocate_aligned_test_alignment_equal_to_page_size() {
let layout = Layout::from_size_align(16, PAGE_SIZE as usize).unwrap();
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(!aligned_ptr.is_null());
assert_eq!((aligned_ptr as usize) % layout.align(), 0);
let original_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::original_pointer(aligned_ptr);
assert!(!original_ptr.is_null());
assert!(original_ptr < aligned_ptr);
unsafe { PagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(aligned_ptr, layout) };
}
#[test]
fn allocate_aligned_test_alignment_greater_than_page_size() {
let layout = Layout::from_size_align(16, PAGE_SIZE as usize * 2).unwrap();
let aligned_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(!aligned_ptr.is_null());
assert_eq!((aligned_ptr as usize) % layout.align(), 0);
let original_ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::original_pointer(aligned_ptr);
assert!(!original_ptr.is_null());
assert!(original_ptr < aligned_ptr);
unsafe { PagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(aligned_ptr, layout) };
}
type NoRealign = NtAlloc<POOL_FLAG_NON_PAGED, DEFAULT_MEMORY_TAG, true, false>;
fn layouts_needing_realignment() -> [Layout; 4] {
let page = PAGE_SIZE as usize;
[
Layout::from_size_align(16, 32).unwrap(),
Layout::from_size_align(64, 64).unwrap(),
Layout::from_size_align(100, page).unwrap(),
Layout::from_size_align(page * 2, page * 2).unwrap(),
]
}
fn layouts_the_pool_aligns() -> [Layout; 4] {
let page = PAGE_SIZE as usize;
[
Layout::from_size_align(64, 8).unwrap(),
Layout::from_size_align(64, MIN_ALIGNMENT).unwrap(),
Layout::from_size_align(page, page).unwrap(),
Layout::from_size_align(page * 2, page).unwrap(),
]
}
#[test]
fn realign_off_ignores_the_alignment_asked_for() {
let alloc = NoRealign::default();
for layout in layouts_needing_realignment() {
assert!(
!NoRealign::is_kernel_aligned(layout),
"{layout:?} should need realignment"
);
let pool_alignment = NoRealign::kernel_alignment(layout.size());
let ptr = NoRealign::allocate_aligned(layout);
assert!(!ptr.is_null(), "{layout:?}");
assert_eq!(ptr.addr() % pool_alignment, 0, "{layout:?}");
unsafe { NoRealign::deallocate(ptr) };
let ptr = unsafe { alloc.alloc(layout) };
assert!(!ptr.is_null(), "{layout:?}");
unsafe { alloc.dealloc(ptr, layout) };
let ptr = unsafe { alloc.alloc_zeroed(layout) };
assert!(!ptr.is_null(), "{layout:?}");
let bytes = unsafe { core::slice::from_raw_parts(ptr, layout.size()) };
assert!(bytes.iter().all(|&b| b == 0), "{layout:?}");
unsafe { alloc.dealloc(ptr, layout) };
}
}
#[test]
fn realign_off_hands_out_only_the_pools_own_pointers() {
let strict = NoRealign::default();
for layout in layouts_the_pool_aligns() {
let ptr = NoRealign::allocate_aligned(layout);
assert!(!ptr.is_null(), "{layout:?}");
assert_eq!(ptr.addr() % layout.align(), 0, "{layout:?}");
unsafe { NoRealign::deallocate(ptr) };
let ptr = unsafe { strict.alloc(layout) };
assert!(!ptr.is_null(), "{layout:?}");
unsafe { strict.dealloc(ptr, layout) };
}
}
#[test]
fn realign_off_resizes_without_realigning() {
let alloc = NoRealign::default();
let page = PAGE_SIZE as usize;
let layout = Layout::from_size_align(page, page).unwrap();
let ptr = unsafe { alloc.alloc(layout) };
assert!(!ptr.is_null());
unsafe { ptr.write_bytes(0x7E, page) };
let shrunk = unsafe { alloc.realloc(ptr, layout, 100) };
assert!(!shrunk.is_null());
assert_eq!(shrunk.addr() % NoRealign::kernel_alignment(100), 0);
let bytes = unsafe { core::slice::from_raw_parts(shrunk, 100) };
assert!(bytes.iter().all(|&b| b == 0x7E));
let shrunk_layout = Layout::from_size_align(100, page).unwrap();
unsafe { alloc.dealloc(shrunk, shrunk_layout) };
}
#[test]
fn realign_is_on_by_default_and_the_aliases_pass_it_through() {
let layout = Layout::from_size_align(64, 64).unwrap();
let ptr = NonPagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(!ptr.is_null());
unsafe { NonPagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(ptr, layout) };
let _: NoRealign = NonPagedAlloc::<DEFAULT_MEMORY_TAG, true, false>::default();
let _: NtAlloc<POOL_FLAG_PAGED, DEFAULT_MEMORY_TAG, true, false> =
PagedAlloc::<DEFAULT_MEMORY_TAG, true, false>::default();
let _: NtAlloc<POOL_FLAG_NON_PAGED> =
NonPagedAlloc::<DEFAULT_MEMORY_TAG, true, true>::default();
}
#[test]
fn align_up_to_advances_from_an_already_aligned_base() {
for alignment in [MIN_ALIGNMENT, 64, PAGE_SIZE as usize] {
let base = alignment * 4;
let aligned = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
without_provenance_mut::<u8>(base),
NonZeroUsize::new(alignment).unwrap(),
) as usize;
assert_eq!(
aligned,
base + alignment,
"alignment {alignment}: expected a full step past an aligned base"
);
}
}
#[test]
fn align_up_to_always_leaves_room_for_the_stash() {
for alignment in [32usize, 64, 128, PAGE_SIZE as usize] {
for step in 0..(alignment / MIN_ALIGNMENT) {
let base = 0x10_0000 + step * MIN_ALIGNMENT;
let aligned = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::align_up_to(
without_provenance_mut::<u8>(base),
NonZeroUsize::new(alignment).unwrap(),
) as usize;
let gap = aligned - base;
assert!(
gap >= POINTER_SIZE,
"alignment {alignment}, base {base:#x}: gap {gap} cannot hold a pointer"
);
assert_eq!(
gap % MIN_ALIGNMENT,
0,
"gap should be a MIN_ALIGNMENT multiple"
);
}
}
}
#[test]
fn zero_size_allocations_never_reach_the_pool() {
assert!(PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate(0).is_null());
for alignment in [1usize, 8, MIN_ALIGNMENT, 32, PAGE_SIZE as usize] {
let layout = Layout::from_size_align(0, alignment).unwrap();
let ptr = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_aligned(layout);
assert!(
ptr.is_null(),
"alignment {alignment}: a zero-size request must not allocate"
);
}
}
#[cfg(feature = "allocator-api")]
#[test]
fn allocator_accepts_zero_sized_layouts() {
for alignment in [1usize, 8, MIN_ALIGNMENT, 32, PAGE_SIZE as usize] {
let layout = Layout::from_size_align(0, alignment).unwrap();
let allocated = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::allocate_slice(layout);
let slice = allocated
.unwrap_or_else(|_| panic!("alignment {alignment}: zero-size layout was rejected"));
assert_eq!(slice.len(), 0, "alignment {alignment}: length must be 0");
assert_eq!(
slice.as_ptr().cast::<u8>() as usize % alignment,
0,
"alignment {alignment}: dangling pointer must still be aligned"
);
unsafe {
PagedAlloc::<DEFAULT_MEMORY_TAG, true>::deallocate_aligned(
slice.as_ptr().cast::<u8>(),
layout,
);
}
}
}
#[cfg(feature = "allocator-api")]
#[test]
fn realign_off_serves_through_the_allocator_api() {
let alloc = NoRealign::default();
for layout in layouts_needing_realignment()
.into_iter()
.chain(layouts_the_pool_aligns())
{
let block = alloc.allocate(layout).unwrap();
assert_eq!(block.len(), layout.size());
let ptr = block.cast::<u8>().as_ptr();
assert_eq!(ptr.addr() % NoRealign::kernel_alignment(layout.size()), 0);
unsafe { alloc.deallocate(block.cast(), layout) };
let block = alloc.allocate_zeroed(layout).unwrap();
let bytes = unsafe { block.as_ref() };
assert!(bytes.iter().all(|&b| b == 0));
unsafe { alloc.deallocate(block.cast(), layout) };
}
let empty = Layout::from_size_align(0, 64).unwrap();
let block = alloc.allocate(empty).unwrap();
assert_eq!(block.len(), 0);
assert_eq!(block.cast::<u8>().as_ptr().addr() % 64, 0);
unsafe { alloc.deallocate(block.cast(), empty) };
}
#[cfg(feature = "allocator-api")]
#[test]
fn allocator_grow_from_zero_and_shrink_to_zero() {
let allocator = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::default();
let empty_layout = Layout::from_size_align(0, MIN_ALIGNMENT).unwrap();
let full_layout = Layout::from_size_align(64, MIN_ALIGNMENT).unwrap();
let empty = allocator
.allocate(empty_layout)
.expect("zero-size allocate");
assert_eq!(empty.len(), 0);
let grown =
unsafe { allocator.grow(empty.cast(), empty_layout, full_layout) }.expect("grow from zero");
assert_eq!(grown.len(), 64);
let shrunk = unsafe { allocator.shrink(grown.cast(), full_layout, empty_layout) }
.expect("shrink to zero");
assert_eq!(shrunk.len(), 0);
unsafe { allocator.deallocate(shrunk.cast(), empty_layout) };
}
#[cfg(feature = "allocator-api")]
#[test]
fn allocator_zeroed_accepts_zero_sized_layouts() {
let allocator = PagedAlloc::<DEFAULT_MEMORY_TAG, true>::default();
let layout = Layout::from_size_align(0, 32).unwrap();
let empty = allocator
.allocate_zeroed(layout)
.expect("zero-size allocate_zeroed");
assert_eq!(empty.len(), 0);
unsafe { allocator.deallocate(empty.cast(), layout) };
}
#[test]
fn kernel_allocate_guards_zero_without_reaching_the_pool() {
assert!(PagedAlloc::<DEFAULT_MEMORY_TAG, true>::kernel_allocate(0).is_null());
}
#[cfg(feature = "allocator-api")]
#[test]
fn free_path_decision_cannot_flip() {
type Alloc = PagedAlloc<DEFAULT_MEMORY_TAG, true>;
let page = PAGE_SIZE as usize;
for shift in 0..14u32 {
let align = 1usize << shift;
let bands = (1..=3).flat_map(|m| (m * page - 2)..=(m * page + 2));
for size in (1usize..=200).chain(bands) {
let Ok(layout) = Layout::from_size_align(size, align) else {
continue;
};
let stashed = !Alloc::is_kernel_aligned(layout);
let slice = Alloc::allocate_slice(layout).expect("allocation");
let reported = slice.len();
unsafe { Alloc::deallocate_aligned(slice.as_ptr().cast::<u8>(), layout) };
assert_eq!(
reported, size,
"size {size} align {align}: allocate_slice must report the \
requested size, or the fitting range widens"
);
let mut probe = size;
while let Ok(other) = Layout::from_size_align(probe, align) {
assert_eq!(
!Alloc::is_kernel_aligned(other),
stashed,
"size {size} align {align}: freeing with size {probe} \
(legal, max is {reported}) flips the stash decision"
);
if probe >= reported {
break;
}
probe = ((probe / page) + 1) * page;
if probe > reported {
probe = reported;
}
}
}
}
}
#[test]
fn allocations_come_back_zeroed() {
type Alloc = PagedAlloc<DEFAULT_MEMORY_TAG, true>;
const { assert!(Alloc::POOL_ZEROES, "the default aliases must zero") };
for &(size, align) in &[(256usize, 16usize), (256, 64), (100, 4096), (4096, 4096)] {
let layout = Layout::from_size_align(size, align).unwrap();
let first = Alloc::allocate_aligned(layout);
assert!(!first.is_null());
unsafe { first.write_bytes(0xAB, size) };
unsafe { Alloc::deallocate_aligned(first, layout) };
let second = Alloc::allocate_aligned(layout);
assert!(!second.is_null());
let dirty = (0..size)
.filter(|i| unsafe { *second.add(*i) } != 0)
.count();
unsafe { Alloc::deallocate_aligned(second, layout) };
assert_eq!(
dirty, 0,
"size {size} align {align}: {dirty} bytes were not zeroed"
);
}
}
#[test]
fn realignment_stash_stays_out_of_the_zeroed_region() {
type Alloc = PagedAlloc<DEFAULT_MEMORY_TAG, true>;
for &(size, align) in &[(64usize, 64usize), (100, 128), (16, 4096)] {
let layout = Layout::from_size_align(size, align).unwrap();
assert!(!Alloc::is_kernel_aligned(layout), "case must realign");
let ptr = Alloc::allocate_aligned(layout);
assert!(!ptr.is_null());
let original = Alloc::original_pointer(ptr);
assert!(original < ptr, "the stash must precede the region");
let dirty = (0..size).filter(|i| unsafe { *ptr.add(*i) } != 0).count();
unsafe { Alloc::deallocate_aligned(ptr, layout) };
assert_eq!(dirty, 0, "size {size} align {align}: region was not zeroed");
}
}
#[test]
fn zeroing_entry_points_honour_their_guarantee() {
type Alloc = PagedAlloc<DEFAULT_MEMORY_TAG, true>;
let allocator = Alloc::default();
for &(size, align) in &[(256usize, 16usize), (256, 64), (4096, 4096)] {
let layout = Layout::from_size_align(size, align).unwrap();
let ptr = unsafe { allocator.alloc_zeroed(layout) };
assert!(!ptr.is_null());
let dirty = (0..size).filter(|i| unsafe { *ptr.add(*i) } != 0).count();
unsafe { allocator.dealloc(ptr, layout) };
assert_eq!(dirty, 0, "alloc_zeroed left {dirty} non-zero bytes");
#[cfg(feature = "allocator-api")]
{
let slice = allocator.allocate_zeroed(layout).expect("allocate_zeroed");
assert_eq!(slice.len(), size);
let base = slice.as_ptr().cast::<u8>();
let dirty = (0..size).filter(|i| unsafe { *base.add(*i) } != 0).count();
unsafe { allocator.deallocate(slice.cast(), layout) };
assert_eq!(dirty, 0, "allocate_zeroed left {dirty} non-zero bytes");
}
}
}
#[test]
fn an_uninitialized_pool_still_zeroes_where_it_promises_to() {
type Uninit =
NtAlloc<{ POOL_FLAG_NON_PAGED | POOL_FLAG_UNINITIALIZED }, DEFAULT_MEMORY_TAG, true>;
const {
assert!(
!Uninit::POOL_ZEROES,
"this configuration opts out of zeroing"
);
}
let allocator = Uninit::default();
let size = 512usize;
let layout = Layout::from_size_align(size, 64).unwrap();
let dirtied = Uninit::allocate_aligned(layout);
assert!(!dirtied.is_null());
unsafe { dirtied.write_bytes(0xAB, size) };
unsafe { Uninit::deallocate_aligned(dirtied, layout) };
let ptr = unsafe { allocator.alloc_zeroed(layout) };
assert!(!ptr.is_null());
let dirty = (0..size).filter(|i| unsafe { *ptr.add(*i) } != 0).count();
unsafe { allocator.dealloc(ptr, layout) };
assert_eq!(dirty, 0, "alloc_zeroed left {dirty} bytes unzeroed");
#[cfg(feature = "allocator-api")]
{
let dirtied = Uninit::allocate_aligned(layout);
assert!(!dirtied.is_null());
unsafe { dirtied.write_bytes(0xCD, size) };
unsafe { Uninit::deallocate_aligned(dirtied, layout) };
let slice = allocator.allocate_zeroed(layout).expect("allocate_zeroed");
let base = slice.as_ptr().cast::<u8>();
let dirty = (0..size).filter(|i| unsafe { *base.add(*i) } != 0).count();
unsafe { allocator.deallocate(slice.cast(), layout) };
assert_eq!(dirty, 0, "allocate_zeroed left {dirty} bytes unzeroed");
}
}
#[test]
fn zero_size_meets_the_zeroing_paths() {
type Zeroing = PagedAlloc<DEFAULT_MEMORY_TAG, true>;
type NonZeroing =
NtAlloc<{ POOL_FLAG_NON_PAGED | POOL_FLAG_UNINITIALIZED }, DEFAULT_MEMORY_TAG, true>;
const { assert!(Zeroing::POOL_ZEROES) };
const { assert!(!NonZeroing::POOL_ZEROES) };
for align in [1usize, 8, MIN_ALIGNMENT, 64, PAGE_SIZE as usize] {
let layout = Layout::from_size_align(0, align).unwrap();
let zeroing = unsafe { Zeroing::default().alloc_zeroed(layout) };
let non_zeroing = unsafe { NonZeroing::default().alloc_zeroed(layout) };
assert!(
zeroing.is_null(),
"align {align}: alloc_zeroed must be null"
);
assert!(
non_zeroing.is_null(),
"align {align}: alloc_zeroed must be null without pool zeroing"
);
#[cfg(feature = "allocator-api")]
{
let zeroing_slice = Zeroing::default()
.allocate_zeroed(layout)
.expect("zero-size allocate_zeroed on a zeroing pool");
let non_zeroing_slice = NonZeroing::default()
.allocate_zeroed(layout)
.expect("zero-size allocate_zeroed on a non-zeroing pool");
for (label, slice) in [
("zeroing", zeroing_slice),
("non-zeroing", non_zeroing_slice),
] {
assert_eq!(slice.len(), 0, "align {align} ({label}): length must be 0");
assert_eq!(
slice.as_ptr().cast::<u8>() as usize % align,
0,
"align {align} ({label}): pointer must still be aligned"
);
}
unsafe {
Zeroing::deallocate_aligned(zeroing_slice.as_ptr().cast::<u8>(), layout);
NonZeroing::deallocate_aligned(non_zeroing_slice.as_ptr().cast::<u8>(), layout);
}
}
}
}
#[test]
fn tag_rules_follow_the_documented_format() {
let valid = [
*b"Rust",
*b"MyDr",
*b"1234",
*b"ab\0\0",
*b"A\0\0\0",
*b"a b ",
*b"~ok~",
*b"---1",
*b"BIG\0",
];
for bytes in valid {
let tag = u32::from_ne_bytes(bytes);
assert!(tag_is_well_formed(tag), "{bytes:?} should be well-formed");
assert!(
tag_has_letter_or_digit(tag),
"{bytes:?} should have a letter or digit"
);
assert_ne!(
tag, BIG_POOL_TAG,
"{bytes:?} should not be the reserved tag"
);
}
let malformed = [
*b"\0abc",
*b"a\0bc",
*b"ab\0c",
*b"\0\0\0a",
[0x1F, b'a', b'b', b'c'],
[b'a', 0x7F, b'b', b'c'],
[b'R', b'u', b's', 0x80],
[0xFF; 4],
[0; 4],
];
for bytes in malformed {
assert!(
!tag_is_well_formed(u32::from_ne_bytes(bytes)),
"{bytes:?} should not be well-formed"
);
}
for bytes in [*b" ", *b"!!!!", *b"-~-~", *b" \0\0\0"] {
let tag = u32::from_ne_bytes(bytes);
assert!(tag_is_well_formed(tag), "{bytes:?} should be well-formed");
assert!(
!tag_has_letter_or_digit(tag),
"{bytes:?} should have no letter or digit"
);
}
assert_eq!(BIG_POOL_TAG.to_ne_bytes(), *b"BIG ");
}
#[test]
fn a_zero_padded_tag_allocates() {
type Short = NtAlloc<POOL_FLAG_NON_PAGED, { u32::from_ne_bytes(*b"ab\0\0") }>;
let ptr = Short::allocate(64);
assert!(!ptr.is_null());
unsafe { Short::deallocate(ptr) };
}
#[cfg(feature = "allocator-api-markers")]
#[test]
fn the_marker_traits_are_implemented() {
fn assert_markers<A: StaticAllocator + AllocatorClone>() {}
assert_markers::<PagedAlloc>();
assert_markers::<NonPagedAlloc>();
}