1use core::slice;
2use std::alloc::{GlobalAlloc, Layout};
3
4use zeroize::Zeroize;
5
6pub struct ZeroizingAllocator<Alloc: GlobalAlloc>(pub Alloc);
23
24unsafe impl<T: GlobalAlloc> GlobalAlloc for ZeroizingAllocator<T> {
25 unsafe fn alloc(&self, layout: Layout) -> *mut u8 {
26 self.0.alloc(layout)
27 }
28
29 unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) {
30 slice::from_raw_parts_mut(ptr, layout.size()).zeroize();
31
32 self.0.dealloc(ptr, layout);
33 }
34
35 unsafe fn alloc_zeroed(&self, layout: Layout) -> *mut u8 {
36 self.0.alloc_zeroed(layout)
37 }
38}
39
40#[cfg(test)]
41mod tests {
42 #[test]
43 #[ignore = "It produces inconsistent results on some platforms"]
44 fn string() {
45 let s = String::from("hello");
46
47 let p1 = s.as_str().as_ptr();
48 let c1 = s.capacity();
49
50 assert_eq!(
51 unsafe { std::slice::from_raw_parts(p1, c1) },
52 b"hello",
53 "String is not at the expected memory location"
54 );
55
56 drop(s);
57
58 assert_eq!(
59 unsafe { std::slice::from_raw_parts(p1, c1) },
60 [0, 0, 0, 0, 0],
61 "memory was not zeroized after dropping the string"
62 );
63 }
64
65 #[test]
66 #[ignore = "It produces inconsistent results on some platforms"]
67 fn string_expand() {
68 let mut s = String::from("hello");
69
70 let p1 = s.as_str().as_ptr();
71 let c1 = s.capacity();
72
73 assert_eq!(unsafe { std::slice::from_raw_parts(p1, c1) }, b"hello");
74
75 s.push_str(" world");
76
77 let p2 = s.as_str().as_ptr();
78 let c2 = s.capacity();
79
80 assert_ne!(p1, p2);
82 assert_eq!(
83 unsafe { std::slice::from_raw_parts(p1, c1) },
84 [0, 0, 0, 0, 0],
85 "old string was not zeroized"
86 );
87
88 assert_eq!(
89 unsafe { std::slice::from_raw_parts(p2, c2) },
90 b"hello world"
91 );
92
93 drop(s);
95
96 assert_eq!(
97 unsafe { std::slice::from_raw_parts(p2, c2) },
98 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
99 "expanded string was not zeroized"
100 );
101 }
102
103 #[test]
104 #[ignore = "It produces inconsistent results on some platforms"]
105 fn vec() {
106 let v = vec![1, 2, 3, 4, 5];
107
108 let p1 = v.as_slice().as_ptr();
109 let c1 = v.capacity();
110
111 assert_eq!(
112 unsafe { std::slice::from_raw_parts(p1, c1) },
113 [1, 2, 3, 4, 5],
114 "vec is not at the expected memory location"
115 );
116
117 drop(v);
118
119 assert_eq!(
120 unsafe { std::slice::from_raw_parts(p1, c1) },
121 [0, 0, 0, 0, 0],
122 "vec was not zeroized after dropping"
123 );
124 }
125
126 #[test]
127 #[ignore = "It produces inconsistent results on some platforms"]
128 fn vec_expand() {
129 let mut v = vec![1, 2, 3, 4, 5];
130
131 let p1 = v.as_slice().as_ptr();
132 let c1 = v.capacity();
133
134 assert_eq!(
135 unsafe { std::slice::from_raw_parts(p1, c1) },
136 [1, 2, 3, 4, 5],
137 "vec is not at the expected memory location"
138 );
139
140 v.extend_from_slice(&[6, 7, 8, 9, 10]);
141
142 let p2 = v.as_slice().as_ptr();
143 let c2 = v.capacity();
144
145 assert_ne!(p1, p2);
147 assert_eq!(
148 unsafe { std::slice::from_raw_parts(p1, c1) },
149 [0, 0, 0, 0, 0],
150 "old vec was not zeroized"
151 );
152
153 assert_eq!(
154 unsafe { std::slice::from_raw_parts(p2, c2) },
155 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
156 );
157
158 drop(v);
160
161 assert_eq!(
162 unsafe { std::slice::from_raw_parts(p2, c2) },
163 [0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
164 "expanded vec was not zeroized"
165 );
166 }
167}