static PHASE_LOCK: std::sync::Mutex<()> = std::sync::Mutex::new(());
#[global_allocator]
static A: zk_alloc::ZkAllocator = zk_alloc::ZkAllocator;
#[test]
fn phase_guard_runs_end_phase_on_panic() {
let _lock = PHASE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
use std::panic;
panic::set_hook(Box::new(|_| {}));
let _ = vec![0u8; 1024];
let r = panic::catch_unwind(panic::AssertUnwindSafe(|| {
zk_alloc::phase(|| panic!("simulated"))
}));
assert!(r.is_err());
let post_panic: Vec<u8> = vec![0xCC; 8192];
let post_panic_ptr = post_panic.as_ptr() as usize;
zk_alloc::phase(|| {
let big: Vec<u8> = vec![0x33; 1 << 20];
let big_ptr = big.as_ptr() as usize;
let big_end = big_ptr + big.len();
let in_big_range = post_panic_ptr >= big_ptr && post_panic_ptr < big_end;
eprintln!(
"post_panic_ptr=0x{post_panic_ptr:x} big=[0x{big_ptr:x}, 0x{big_end:x}) \
in_range={in_big_range}"
);
assert!(
!in_big_range,
"PhaseGuard didn't run end_phase during unwind — post_panic landed in arena"
);
});
let _ = panic::take_hook();
assert!(
post_panic.iter().all(|&b| b == 0xCC),
"post_panic was corrupted; PhaseGuard didn't end the phase on panic"
);
eprintln!("PhaseGuard fix verified: panic unwound through phase, end_phase ran, post-panic Vec safe in System");
}
#[test]
fn phase_guard_runs_end_phase_on_normal_return() {
let _lock = PHASE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let v = zk_alloc::phase(|| vec![0xAB_u8; 8192]);
let after: Vec<u8> = vec![0xCD_u8; 8192];
zk_alloc::phase(|| {
let _filler: Vec<u8> = vec![0x77_u8; 1 << 20];
});
assert!(
after.iter().all(|&b| b == 0xCD),
"after-phase Vec was corrupted"
);
std::hint::black_box(v);
}
#[test]
#[should_panic(expected = "phases must not nest")]
fn nested_phase_guards_panic() {
let _lock = PHASE_LOCK.lock().unwrap_or_else(|e| e.into_inner());
let _ = zk_alloc::phase(|| zk_alloc::phase(|| 42_u64));
}