use super::*;
#[test]
fn test_basic_allocation() {
type Alloc = MemoryPoolAllocator<1024, 64>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 8).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
assert_eq!(ptr as usize % 8, 0);
assert!(allocator.try_deallocate(ptr).is_ok());
#[cfg(feature = "statistics")]
{
let stats = allocator.stats.lock();
assert_eq!(stats.allocated_chunks, 0);
}
}
#[test]
fn test_multiple_allocations() {
type Alloc = MemoryPoolAllocator<1024, 64>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 8).unwrap();
let mut ptrs = [core::ptr::null_mut(); 10];
let mut count = 0;
for i in 0..10 {
match allocator.try_allocate(layout) {
Ok(ptr) => {
ptrs[i] = ptr;
count += 1;
}
Err(_) => break,
}
}
assert!(count > 0);
for i in 0..count {
assert_eq!(ptrs[i] as usize % 8, 0);
for j in (i + 1)..count {
assert_ne!(ptrs[i], ptrs[j]);
}
}
for i in 0..count {
assert!(allocator.try_deallocate(ptrs[i]).is_ok());
}
#[cfg(feature = "statistics")]
{
let stats = allocator.stats.lock();
assert_eq!(stats.allocated_chunks, 0);
}
}
#[test]
fn test_complex_alignment() {
type Alloc = MemoryPoolAllocator<1024, 64>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout1 = Layout::from_size_align(10, 1).unwrap();
let layout2 = Layout::from_size_align(20, 4).unwrap();
let layout3 = Layout::from_size_align(30, 16).unwrap();
let ptr1 = allocator.try_allocate(layout1).unwrap();
let ptr2 = allocator.try_allocate(layout2).unwrap();
let ptr3 = allocator.try_allocate(layout3).unwrap();
assert_eq!(ptr1 as usize % 1, 0);
assert_eq!(ptr2 as usize % 4, 0);
assert_eq!(ptr3 as usize % 16, 0);
allocator.try_deallocate(ptr1).unwrap();
allocator.try_deallocate(ptr2).unwrap();
allocator.try_deallocate(ptr3).unwrap();
assert_eq!(allocator.count_free_chunks(), 64);
assert_eq!(allocator.count_allocated_chunks(), 0);
}
#[test]
fn test_alignment_handling() {
type Alloc = MemoryPoolAllocator<2048, 32>;
#[repr(align(32))]
struct Aligned {
mem: [u8; 1024],
}
let mut aligned = Aligned { mem: [0; 1024] };
let allocator = unsafe { Alloc::new(aligned.mem.as_mut_ptr()) };
let layout1 = Layout::from_size_align(32, 16).unwrap();
let ptr1 = allocator.try_allocate(layout1).unwrap();
assert_eq!(ptr1 as usize % 16, 0);
let layout2 = Layout::from_size_align(64, 32).unwrap();
let ptr2 = allocator.try_allocate(layout2).unwrap();
assert_eq!(ptr2 as usize % 32, 0);
allocator.try_deallocate(ptr1).unwrap();
allocator.try_deallocate(ptr2).unwrap();
}
#[test]
#[cfg(feature = "statistics")]
fn test_error_handling() {
type Alloc = MemoryPoolAllocator<512, 32>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 8).unwrap();
for _ in 0..32 {
assert!(allocator.try_allocate(layout).is_ok());
}
assert!(allocator.try_allocate(layout).is_err());
let stats = allocator.stats.lock();
assert!(stats.allocation_errors > 0);
}
#[test]
fn test_full_pool() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 8).unwrap();
let ptr1 = allocator.try_allocate(layout).unwrap();
let ptr2 = allocator.try_allocate(layout).unwrap();
let ptr3 = allocator.try_allocate(layout).unwrap();
let ptr4 = allocator.try_allocate(layout).unwrap();
assert!(allocator.try_allocate(layout).is_err());
allocator.try_deallocate(ptr2).unwrap();
let ptr5 = allocator.try_allocate(layout).unwrap();
allocator.try_deallocate(ptr1).unwrap();
allocator.try_deallocate(ptr3).unwrap();
allocator.try_deallocate(ptr4).unwrap();
allocator.try_deallocate(ptr5).unwrap();
}
#[test]
fn test_allocation_with_alignment_padding() {
type Alloc = MemoryPoolAllocator<256, 16>;
#[repr(align(32))]
struct AlignedPool {
mem: [u8; 512],
}
let mut pool = AlignedPool { mem: [0; 512] };
let allocator = unsafe { Alloc::new(pool.mem.as_mut_ptr()) };
let basic_layout = Layout::from_size_align(16, 1).unwrap();
let align_layout = Layout::from_size_align(16, 32).unwrap();
let first = allocator.try_allocate(basic_layout).unwrap();
let second = allocator.try_allocate(basic_layout).unwrap();
let third = allocator.try_allocate(basic_layout).unwrap();
allocator.try_deallocate(second).unwrap();
allocator.try_deallocate(third).unwrap();
let aligned_ptr = allocator.try_allocate(align_layout).unwrap();
assert_eq!(aligned_ptr as usize % 32, 0);
let fourth = allocator.try_allocate(basic_layout).unwrap();
allocator.try_deallocate(first).unwrap();
allocator.try_deallocate(aligned_ptr).unwrap();
allocator.try_deallocate(fourth).unwrap();
assert_eq!(allocator.count_allocated_chunks(), 0);
assert_eq!(allocator.count_free_chunks(), 16);
}
#[test]
#[cfg(feature = "zero-on-free")]
fn test_memory_zeroing() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 8).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
unsafe {
let data_ptr = ptr.add(8);
core::ptr::write_bytes(data_ptr, 0xAB, 8);
}
allocator.try_deallocate(ptr).unwrap();
let ptr2 = allocator.try_allocate(layout).unwrap();
let mut buffer = [0u8; 8];
unsafe {
let data_ptr = ptr2.add(8);
core::ptr::copy_nonoverlapping(data_ptr, buffer.as_mut_ptr(), 8);
}
assert!(buffer.iter().all(|&b| b == 0));
allocator.try_deallocate(ptr2).unwrap();
}
#[test]
fn test_coalescing() {
type Alloc = MemoryPoolAllocator<64, 8>; let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
assert_eq!(allocator.count_free_chunks(), 8);
let layout = Layout::from_size_align(8, 1).unwrap(); let ptr1 = allocator.try_allocate(layout).unwrap();
let ptr2 = allocator.try_allocate(layout).unwrap();
let ptr3 = allocator.try_allocate(layout).unwrap();
assert_eq!(allocator.count_free_chunks(), 5);
assert_eq!(allocator.count_allocated_chunks(), 3);
allocator.try_deallocate(ptr2).unwrap();
assert_eq!(allocator.count_free_chunks(), 6);
assert_eq!(allocator.count_allocated_chunks(), 2);
allocator.try_deallocate(ptr1).unwrap();
assert_eq!(allocator.count_free_chunks(), 7);
assert_eq!(allocator.count_allocated_chunks(), 1);
allocator.try_deallocate(ptr3).unwrap();
assert_eq!(allocator.count_free_chunks(), 8);
assert_eq!(allocator.count_allocated_chunks(), 0);
}
struct BadVec<'a, T> {
size: usize,
slice: &'a mut [T],
}
impl<'a, T> BadVec<'a, T> {
fn new(size: usize, slice: &'a mut [T]) -> BadVec<'a, T> {
BadVec { size, slice }
}
fn set(&mut self, idx: usize, data: T) -> Result<(), ()> {
if idx < self.size {
self.slice[idx] = data;
Ok(())
} else {
Err(())
}
}
fn get(&mut self, idx: usize) -> Option<&mut T> {
if idx < self.size {
Some(&mut self.slice[idx])
} else {
None
}
}
}
#[test]
fn try_out_bad_vec() {
type Alloc = MemoryPoolAllocator<64, 8>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(10, 8).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
let slice = unsafe { core::slice::from_raw_parts_mut(ptr, 10) };
let mut my_bad_vec = BadVec::new(10, slice);
for i in 0..10 {
my_bad_vec.set(i, i as u8).unwrap();
}
match my_bad_vec.get(5) {
Some(data) => {
assert_eq!(*data, 5);
}
None => {
panic!("No data found!");
}
}
}
#[test]
fn test_zero_size_allocation() {
type Alloc = MemoryPoolAllocator<64, 8>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(0, 1).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
assert!(!ptr.is_null());
}
#[test]
fn test_maximum_size_allocation() {
type Alloc = MemoryPoolAllocator<64, 4>; let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(64, 1).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
assert!(!ptr.is_null());
assert_eq!(allocator.count_free_chunks(), 0);
assert_eq!(allocator.count_allocated_chunks(), 4);
let small_layout = Layout::from_size_align(1, 1).unwrap();
assert!(allocator.try_allocate(small_layout).is_err());
allocator.try_deallocate(ptr).unwrap();
assert_eq!(allocator.count_free_chunks(), 4);
}
#[test]
fn test_oversized_allocation() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(128, 1).unwrap();
assert!(allocator.try_allocate(layout).is_err());
assert_eq!(allocator.count_free_chunks(), 4);
assert_eq!(allocator.count_allocated_chunks(), 0);
}
#[test]
fn test_power_of_two_alignments() {
type Alloc = MemoryPoolAllocator<1024, 64>; let mut mem = [0u8; 1024];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let alignments = [1, 2, 4, 8, 16, 32, 64];
let mut ptrs = [0u8 as *mut u8; 7];
for i in 0..7 {
let layout = Layout::from_size_align(8, alignments[i]).unwrap();
if let Ok(ptr) = allocator.try_allocate(layout) {
assert_eq!(
ptr as usize % alignments[i],
0,
"Failed alignment for {}",
alignments[i]
);
ptrs[i] = ptr;
}
}
for ptr in ptrs {
allocator.try_deallocate(ptr).unwrap();
}
}
#[test]
fn test_large_alignment_requirements() {
type Alloc = MemoryPoolAllocator<512, 32>; let mut mem = [0u8; 512];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(8, 64).unwrap();
if let Ok(ptr) = allocator.try_allocate(layout) {
assert_eq!(ptr as usize % 64, 0);
allocator.try_deallocate(ptr).unwrap();
}
let layout = Layout::from_size_align(8, 1024).unwrap();
assert!(allocator.try_allocate(layout).is_err());
}
#[test]
fn test_fragmentation_pattern() {
type Alloc = MemoryPoolAllocator<128, 16>; let mut mem = [0u8; 128];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(8, 1).unwrap();
let mut ptrs = [(0usize, 0u8 as *mut u8); 8];
for i in 0..8 {
if let Ok(ptr) = allocator.try_allocate(layout) {
ptrs[i] = (i, ptr);
}
}
for (i, ptr) in ptrs.iter() {
if i % 2 == 0 {
allocator.try_deallocate(*ptr).unwrap();
}
}
let large_layout = Layout::from_size_align(16, 1).unwrap(); let large_ptr = allocator.try_allocate(large_layout);
for (i, ptr) in ptrs.iter() {
if i % 2 == 1 {
allocator.try_deallocate(*ptr).unwrap();
}
}
if let Ok(ptr) = large_ptr {
allocator.try_deallocate(ptr).unwrap();
}
assert_eq!(allocator.count_free_chunks(), 16);
}
#[test]
fn test_alternating_alloc_free() {
type Alloc = MemoryPoolAllocator<64, 8>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(8, 1).unwrap();
for _ in 0..100 {
let ptr = allocator.try_allocate(layout).unwrap();
allocator.try_deallocate(ptr).unwrap();
}
assert_eq!(allocator.count_free_chunks(), 8);
assert_eq!(allocator.count_allocated_chunks(), 0);
let full_layout = Layout::from_size_align(64, 1).unwrap();
let full_ptr = allocator.try_allocate(full_layout).unwrap();
allocator.try_deallocate(full_ptr).unwrap();
}
#[test]
fn test_double_free_detection() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(16, 1).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
assert!(allocator.try_deallocate(ptr).is_ok());
assert!(allocator.try_deallocate(ptr).is_err());
}
#[test]
fn test_invalid_pointer_deallocation() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let fake_ptr = 0x1000 as *mut u8;
assert!(allocator.try_deallocate(fake_ptr).is_err());
assert!(allocator.try_deallocate(core::ptr::null_mut()).is_err());
}
#[test]
fn test_invalid_layout() {
type Alloc = MemoryPoolAllocator<64, 4>;
let mut mem = [0u8; 64];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
if let Ok(layout) = Layout::from_size_align(8, 128) {
assert!(allocator.try_allocate(layout).is_err());
}
}
#[test]
fn test_single_byte_allocations() {
type Alloc = MemoryPoolAllocator<32, 32>; let mut mem = [0u8; 32];
let allocator = unsafe { Alloc::new(mem.as_mut_ptr()) };
let layout = Layout::from_size_align(1, 1).unwrap();
let mut ptrs = [0u8 as *mut u8; 32];
for i in 0..32 {
if let Ok(ptr) = allocator.try_allocate(layout) {
ptrs[i] = ptr;
} else {
break;
}
}
assert_eq!(allocator.count_allocated_chunks(), 32);
assert_eq!(allocator.count_free_chunks(), 0);
assert!(allocator.try_allocate(layout).is_err());
for ptr in ptrs {
allocator.try_deallocate(ptr).unwrap();
}
assert_eq!(allocator.count_free_chunks(), 32);
}
#[test]
fn test_unaligned_pool_base() {
type Alloc = MemoryPoolAllocator<64, 8>;
let mut mem = [0u8; 68];
let misaligned_ptr = unsafe { mem.as_mut_ptr().add(3) }; let allocator = unsafe { Alloc::new(misaligned_ptr) };
let layout = Layout::from_size_align(4, 1).unwrap();
let ptr = allocator.try_allocate(layout).unwrap();
let aligned_layout = Layout::from_size_align(4, 16).unwrap();
let result = allocator.try_allocate(aligned_layout);
allocator.try_deallocate(ptr).unwrap();
if let Ok(aligned_ptr) = result {
allocator.try_deallocate(aligned_ptr).unwrap();
}
}