crate::ix!();
#[instrument(level = "trace", skip(ptr))]
pub fn memory_cleanse(ptr: *mut c_void, len: usize) {
if ptr.is_null() || len == 0 {
trace!("memory_cleanse: nothing to do");
return;
}
unsafe {
let mut p = ptr as *mut u8;
for _ in 0..len {
core::ptr::write_volatile(p, 0);
p = p.add(1);
}
compiler_fence(atomic::Ordering::SeqCst);
}
}
#[cfg(test)]
mod test_memory_cleanse {
use super::*;
use core::ffi::c_void;
fn patterned_vec(len: usize, pattern: u8) -> Vec<u8> {
let mut v = Vec::with_capacity(len);
v.resize(len, pattern);
v
}
#[traced_test]
fn test_memory_cleanse_zeroes_buffer() {
const LEN: usize = 32;
const PAT: u8 = 0xAA;
let mut buf = patterned_vec(LEN, PAT);
assert!(buf.iter().all(|&b| b == PAT));
unsafe {
memory_cleanse(buf.as_mut_ptr() as *mut c_void, LEN);
}
assert!(buf.iter().all(|&b| b == 0));
}
#[traced_test]
fn test_memory_cleanse_len_zero_no_overwrite() {
const LEN: usize = 0;
const PAT: u8 = 0x55;
let mut buf = patterned_vec(8, PAT);
unsafe {
memory_cleanse(buf.as_mut_ptr() as *mut c_void, LEN);
}
assert!(buf.iter().all(|&b| b == PAT));
}
#[traced_test]
fn test_memory_cleanse_null_ptr_safe() {
unsafe {
memory_cleanse(core::ptr::null_mut(), 16);
}
assert!(true);
}
#[traced_test]
fn test_memory_cleanse_various_lengths() {
const MAX: usize = 65;
for len in 1..=MAX {
let mut buf = (0..len as u8).collect::<Vec<u8>>();
unsafe {
memory_cleanse(buf.as_mut_ptr() as *mut c_void, len);
}
assert!(
buf.iter().all(|&b| b == 0),
"non‑zero byte found after cleanse for len={len}"
);
}
}
}