#![allow(clippy::unwrap_used, clippy::expect_used)]
use std::alloc::{
GlobalAlloc,
Layout,
System,
};
use std::sync::atomic::{
AtomicUsize,
Ordering,
};
use std::sync::{
Mutex,
MutexGuard,
};
use lib_q_random::LibQRng;
struct MaxSizeAllocator;
static MAX_ALLOC_SIZE: AtomicUsize = AtomicUsize::new(0);
fn record(size: usize) {
MAX_ALLOC_SIZE.fetch_max(size, Ordering::SeqCst);
}
unsafe impl GlobalAlloc for MaxSizeAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
record(layout.size());
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
unsafe { System.dealloc(ptr, layout) }
}
unsafe fn realloc(&self, ptr: *mut u8, layout: Layout, new_size: usize) -> *mut u8 {
record(new_size);
unsafe { System.realloc(ptr, layout, new_size) }
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
record(layout.size());
unsafe { System.alloc_zeroed(layout) }
}
}
#[global_allocator]
static ALLOCATOR: MaxSizeAllocator = MaxSizeAllocator;
static TRACKER_LOCK: Mutex<()> = Mutex::new(());
fn tracker_lock() -> MutexGuard<'static, ()> {
TRACKER_LOCK
.lock()
.unwrap_or_else(|poisoned| poisoned.into_inner())
}
#[test]
fn allocator_tracker_observes_a_deliberate_allocation() {
let _serialized = tracker_lock();
MAX_ALLOC_SIZE.store(0, Ordering::SeqCst);
let v: Vec<u8> = vec![0u8; 4096];
std::hint::black_box(&v);
let seen = MAX_ALLOC_SIZE.load(Ordering::SeqCst);
assert!(
seen >= 4096,
"control allocation of 4096 bytes was not observed by the tracker \
(max seen={seen}) — the harness itself is broken"
);
}
#[test]
fn fill_performs_no_dest_sized_intermediate_allocation() {
let _serialized = tracker_lock();
const DEST_LEN: usize = 1024;
const DEST_BYTES: usize = DEST_LEN * core::mem::size_of::<u32>();
let mut rng = LibQRng::new_secure().expect("failed to create secure RNG");
let mut warmup = [0u8; 32];
rng.fill(&mut warmup);
let mut dest = [0u32; DEST_LEN];
MAX_ALLOC_SIZE.store(0, Ordering::SeqCst);
rng.fill(&mut dest);
let max_seen = MAX_ALLOC_SIZE.load(Ordering::SeqCst);
assert!(
max_seen < DEST_BYTES,
"LibQRng::fill made an allocation of {max_seen} bytes while filling a \
{DEST_BYTES}-byte destination — looks like a reintroduced \
dest-sized intermediate buffer (expected all allocations, if any, \
to be well below the request size)"
);
assert!(dest.iter().any(|&x| x != 0), "fill left dest all zero");
}