#![cfg(all(
feature = "alloc-core",
feature = "alloc-xthread",
feature = "alloc-decommit"
))]
use core::alloc::Layout;
use std::collections::HashSet;
use sefer_alloc::alloc_core::AllocCore;
#[cfg_attr(miri, ignore)] #[test]
fn stale_ring_entry_rejected_by_bump_guard() {
let mut ac = AllocCore::new().expect("primordial");
let layout = Layout::from_size_align(256, 8).unwrap();
let class_idx = ac
.dbg_layout_class_for(layout)
.expect("256 B is a small class");
const N: usize = 60_000;
let mut ptrs = Vec::with_capacity(N);
for _ in 0..N {
let p = ac.alloc(layout);
assert!(!p.is_null());
ptrs.push(p);
}
let mut pushed_ptrs = Vec::new();
for &p in &ptrs {
if ac.dbg_push_to_ring(p, class_idx) {
pushed_ptrs.push(p);
}
}
assert!(
!pushed_ptrs.is_empty(),
"no ring pushes succeeded — segment ring overflow on every block"
);
let stale_ptr = pushed_ptrs[0];
let _ = ac.dbg_push_to_ring(stale_ptr, class_idx);
ac.dbg_drain_all_rings();
let mut ptrs2 = Vec::with_capacity(200);
for _ in 0..200 {
let p = ac.alloc(layout);
assert!(!p.is_null(), "re-alloc returned null after stale drain");
unsafe {
core::ptr::write_bytes(p, 0xBB, 256);
assert_eq!(p.read(), 0xBB, "write/readback failed after stale drain");
}
ptrs2.push(p);
}
let set: HashSet<usize> = ptrs2.iter().map(|&p| p as usize).collect();
assert_eq!(
set.len(),
ptrs2.len(),
"duplicate pointer after stale drain — free-list corruption"
);
for &p in &ptrs2 {
ac.dealloc(p, layout);
}
}
#[test]
fn post_recycle_push_rejected_by_contains_base() {
let mut ac = AllocCore::new().expect("primordial");
let layout = Layout::from_size_align(256, 8).unwrap();
let class_idx = ac
.dbg_layout_class_for(layout)
.expect("256 B is a small class");
const N: usize = 500;
let mut ptrs = Vec::with_capacity(N);
for _ in 0..N {
let p = ac.alloc(layout);
assert!(!p.is_null());
ptrs.push(p);
}
let decommit_before = AllocCore::dbg_decommit_count();
for &p in &ptrs {
ac.dealloc(p, layout);
}
let decommit_after = AllocCore::dbg_decommit_count();
if decommit_after == decommit_before {
return;
}
let recycled_ptr = ptrs.iter().copied().find(|&p| {
ac.dbg_live_count_for(p).is_none()
});
let stale = match recycled_ptr {
Some(p) => p,
None => {
return;
}
};
let pushed = ac.dbg_push_to_ring(stale, class_idx);
assert!(
!pushed,
"push to a recycled segment's ring was accepted — contains_base check missing"
);
let p = ac.alloc(layout);
assert!(!p.is_null(), "alloc failed after post-recycle push test");
ac.dealloc(p, layout);
}