use core::slice;
use std::alloc::{GlobalAlloc, Layout};
use zeroize::Zeroize;
pub struct ZeroizingAllocator<Alloc: GlobalAlloc>(pub Alloc);
unsafe impl<T: GlobalAlloc> GlobalAlloc for ZeroizingAllocator<T> {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
self.0.alloc(layout)
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
slice::from_raw_parts_mut(ptr, layout.size()).zeroize();
self.0.dealloc(ptr, layout);
}
unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
self.0.alloc_zeroed(layout)
}
}
#[cfg(test)]
mod tests {
#[test]
#[ignore = "It produces inconsistent results on some platforms"]
fn string() {
let s = String::from("hello");
let p1 = s.as_str().as_ptr();
let c1 = s.capacity();
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
b"hello",
"String is not at the expected memory location"
);
drop(s);
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[0, 0, 0, 0, 0],
"memory was not zeroized after dropping the string"
);
}
#[test]
#[ignore = "It produces inconsistent results on some platforms"]
fn string_expand() {
let mut s = String::from("hello");
let p1 = s.as_str().as_ptr();
let c1 = s.capacity();
assert_eq!(unsafe { std::slice::from_raw_parts(p1, c1) }, b"hello");
s.push_str(" world");
let p2 = s.as_str().as_ptr();
let c2 = s.capacity();
assert_ne!(p1, p2);
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[0, 0, 0, 0, 0],
"old string was not zeroized"
);
assert_eq!(
unsafe { std::slice::from_raw_parts(p2, c2) },
b"hello world"
);
drop(s);
assert_eq!(
unsafe { std::slice::from_raw_parts(p2, c2) },
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expanded string was not zeroized"
);
}
#[test]
#[ignore = "It produces inconsistent results on some platforms"]
fn vec() {
let v = vec![1, 2, 3, 4, 5];
let p1 = v.as_slice().as_ptr();
let c1 = v.capacity();
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[1, 2, 3, 4, 5],
"vec is not at the expected memory location"
);
drop(v);
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[0, 0, 0, 0, 0],
"vec was not zeroized after dropping"
);
}
#[test]
#[ignore = "It produces inconsistent results on some platforms"]
fn vec_expand() {
let mut v = vec![1, 2, 3, 4, 5];
let p1 = v.as_slice().as_ptr();
let c1 = v.capacity();
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[1, 2, 3, 4, 5],
"vec is not at the expected memory location"
);
v.extend_from_slice(&[6, 7, 8, 9, 10]);
let p2 = v.as_slice().as_ptr();
let c2 = v.capacity();
assert_ne!(p1, p2);
assert_eq!(
unsafe { std::slice::from_raw_parts(p1, c1) },
[0, 0, 0, 0, 0],
"old vec was not zeroized"
);
assert_eq!(
unsafe { std::slice::from_raw_parts(p2, c2) },
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
);
drop(v);
assert_eq!(
unsafe { std::slice::from_raw_parts(p2, c2) },
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expanded vec was not zeroized"
);
}
}