1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
#![no_std]

use core::alloc::{GlobalAlloc, Layout};

pub struct ZeroizingAllocator<Alloc: GlobalAlloc>(pub Alloc);

unsafe fn zero(ptr: *mut u8, size: usize) {
    for i in 0..size {
        core::ptr::write_volatile(ptr.offset(i as isize), 0);
    }
    core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
}

unsafe impl<T> GlobalAlloc for ZeroizingAllocator<T>
where
    T: GlobalAlloc,
{
    unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
        self.0.alloc(layout)
    }

    unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
        zero(ptr, layout.size());
        #[cfg(not(feature = "leaky"))]
        self.0.dealloc(ptr, layout);
    }

    unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
        self.0.alloc_zeroed(layout)
    }
}

#[cfg(all(feature = "leaky", test))]
mod test {
    extern crate std;
    use std::vec::Vec;

    #[global_allocator]
    static ALLOC: super::ZeroizingAllocator<std::alloc::System> =
        super::ZeroizingAllocator(std::alloc::System);

    #[test]
    fn test() {
        let mut a = Vec::with_capacity(2);
        a.push(0xde);
        a.push(0xad);
        let ptr1: *const u8 = &a[0];
        a.push(0xbe);
        a.push(0xef);
        let ptr2: *const u8 = &a[0];
        assert_eq!(&[0xde, 0xad, 0xbe, 0xef], &a[..]);
        assert_eq!(unsafe { ptr1.as_ref() }, Some(&0));
        drop(a);
        assert_eq!(unsafe { ptr2.as_ref() }, Some(&0));
    }
}