Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions zeroize/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,11 @@ default = ["alloc"]
alloc = []
std = ["alloc"]

aarch64 = [] # NOTE: vestigial no-op feature; AArch64 support is always enabled now
aarch64 = [] # NOTE: vestigial no-op feature; AArch64 support is always enabled now
derive = ["zeroize_derive"]
simd = [] # NOTE: MSRV 1.72
simd = [] # NOTE: MSRV 1.72

test-allocator = ["std"]

[package.metadata.docs.rs]
all-features = true
57 changes: 57 additions & 0 deletions zeroize/tests/zeroize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -208,3 +208,60 @@ fn asref() {
let _asmut: &mut [u8] = buffer.as_mut();
let _asref: &[u8] = buffer.as_ref();
}

#[cfg(not(miri))]
#[cfg(feature = "test-allocator")]
mod zeroization_with_custom_allocator {
use super::*;
use core::ptr;
use std::alloc::{GlobalAlloc, Layout, System};
// Allocator that leaks all memory it allocates, thus leaving the memory open for inspection.
struct UnfreeAllocator;
unsafe impl GlobalAlloc for UnfreeAllocator {
unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
unsafe { System.alloc(layout) }
}
unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
// Do nothing, leak memory
let _ = (ptr, layout);
}
}

#[global_allocator]
static UNFREE_ALLOCATOR: UnfreeAllocator = UnfreeAllocator;

#[test]
#[allow(unsafe_code, unused_assignments)]
fn clears_memory_when_scope_ends() {
struct SecretBox<S: Zeroize + ?Sized>(Box<S>);
impl<S: Zeroize + ?Sized> Drop for SecretBox<S> {
fn drop(&mut self) {
self.0.as_mut().zeroize()
}
}

let mut ptr: *const u128 = ptr::null();

unsafe {
{
let secret = SecretBox(Box::new(0xdeadbeef_u128));
let boxptr = &secret as *const SecretBox<u128>;
let boxptr = boxptr as *const *const u128;
ptr = *boxptr;
assert!(!ptr.is_null(), "ptr is null before drop, not ok");
let bytes: &[u8] = core::slice::from_raw_parts(ptr as *const u8, size_of::<u128>());
assert!(
!bytes.iter().all(|&b| b == 0),
"Expected non-zero data, instead found 0s: {:X?}",
bytes
);
}
// Check that the memory is cleared after the scope ends
for _ in 0..size_of::<u128>() {
// This is UB but proooobably fine given the leaking allocator.
let byte = *(ptr as *const u8).add(1);
assert_eq!(byte, 0);
}
}
}
}