1 //! Integration tests for `zeroize_derive` proc macros
2 #![cfg(feature = "zeroize_derive")]
3 
4 use zeroize::{Zeroize, ZeroizeOnDrop};
5 
6 #[test]
derive_tuple_struct_test()7 fn derive_tuple_struct_test() {
8     #[derive(Zeroize, ZeroizeOnDrop)]
9     struct Z([u8; 3]);
10 
11     let mut value = Z([1, 2, 3]);
12     value.zeroize();
13     assert_eq!(&value.0, &[0, 0, 0])
14 }
15 
16 #[test]
17 #[cfg(feature = "alloc")]
derive_struct_test()18 fn derive_struct_test() {
19     #[derive(Zeroize, ZeroizeOnDrop)]
20     struct Z {
21         string: String,
22         vec: Vec<u8>,
23         bytearray: [u8; 3],
24         number: usize,
25         boolean: bool,
26     }
27 
28     let mut value = Z {
29         string: String::from("Hello, world!"),
30         vec: vec![1, 2, 3],
31         bytearray: [4, 5, 6],
32         number: 42,
33         boolean: true,
34     };
35 
36     value.zeroize();
37 
38     assert!(value.string.is_empty());
39     assert!(value.vec.is_empty());
40     assert_eq!(&value.bytearray, &[0, 0, 0]);
41     assert_eq!(value.number, 0);
42     assert!(!value.boolean);
43 }
44 
45 #[test]
derive_enum_test()46 fn derive_enum_test() {
47     #[derive(Zeroize, ZeroizeOnDrop)]
48     enum Z {
49         #[allow(dead_code)]
50         Variant1,
51         Variant2(usize),
52     }
53 
54     let mut value = Z::Variant2(26);
55 
56     value.zeroize();
57 
58     assert!(matches!(value, Z::Variant2(0)));
59 }
60 
61 /// Test that the custom macro actually derived `Drop` for `Z`
62 #[test]
derive_struct_drop()63 fn derive_struct_drop() {
64     #[derive(Zeroize, ZeroizeOnDrop)]
65     struct Z([u8; 3]);
66 
67     assert!(std::mem::needs_drop::<Z>());
68 }
69 
70 /// Test that the custom macro actually derived `Drop` for `Z`
71 #[test]
derive_enum_drop()72 fn derive_enum_drop() {
73     #[allow(dead_code)]
74     #[derive(Zeroize, ZeroizeOnDrop)]
75     enum Z {
76         Variant1,
77         Variant2(usize),
78     }
79 
80     assert!(std::mem::needs_drop::<Z>());
81 }
82 
83 /// Test that the custom macro actually derived `Drop` for `Z`
84 #[test]
derive_struct_only_drop()85 fn derive_struct_only_drop() {
86     #[derive(ZeroizeOnDrop)]
87     struct Z([u8; 3]);
88 
89     assert!(std::mem::needs_drop::<Z>());
90 }
91 
92 /// Test that the custom macro actually derived `Drop` for `Z`
93 #[test]
derive_enum_only_drop()94 fn derive_enum_only_drop() {
95     #[allow(dead_code)]
96     #[derive(ZeroizeOnDrop)]
97     enum Z {
98         Variant1,
99         Variant2(usize),
100     }
101 
102     assert!(std::mem::needs_drop::<Z>());
103 }
104 
105 /// Test that `Drop` is not derived in the following case by defining a
106 /// `Drop` impl which should conflict if the custom derive defined one too
107 #[allow(dead_code)]
108 #[derive(Zeroize)]
109 struct ZeroizeNoDropStruct([u8; 3]);
110 
111 impl Drop for ZeroizeNoDropStruct {
drop(&mut self)112     fn drop(&mut self) {}
113 }
114 
115 #[allow(dead_code)]
116 #[derive(Zeroize)]
117 enum ZeroizeNoDropEnum {
118     Variant([u8; 3]),
119 }
120 
121 impl Drop for ZeroizeNoDropEnum {
drop(&mut self)122     fn drop(&mut self) {}
123 }
124 
125 #[test]
126 #[cfg(feature = "alloc")]
derive_struct_skip()127 fn derive_struct_skip() {
128     #[derive(Zeroize, ZeroizeOnDrop)]
129     struct Z {
130         string: String,
131         vec: Vec<u8>,
132         #[zeroize(skip)]
133         bytearray: [u8; 3],
134         number: usize,
135         boolean: bool,
136     }
137 
138     let mut value = Z {
139         string: String::from("Hello, world!"),
140         vec: vec![1, 2, 3],
141         bytearray: [4, 5, 6],
142         number: 42,
143         boolean: true,
144     };
145 
146     value.zeroize();
147 
148     assert!(value.string.is_empty());
149     assert!(value.vec.is_empty());
150     assert_eq!(&value.bytearray, &[4, 5, 6]);
151     assert_eq!(value.number, 0);
152     assert!(!value.boolean);
153 }
154 
155 #[test]
156 #[cfg(feature = "alloc")]
derive_enum_skip()157 fn derive_enum_skip() {
158     #[derive(Zeroize, ZeroizeOnDrop)]
159     enum Z {
160         #[allow(dead_code)]
161         Variant1,
162         #[zeroize(skip)]
163         Variant2([u8; 3]),
164         #[zeroize(skip)]
165         Variant3 {
166             string: String,
167             vec: Vec<u8>,
168             bytearray: [u8; 3],
169             number: usize,
170             boolean: bool,
171         },
172         Variant4 {
173             string: String,
174             vec: Vec<u8>,
175             #[zeroize(skip)]
176             bytearray: [u8; 3],
177             number: usize,
178             boolean: bool,
179         },
180     }
181 
182     let mut value = Z::Variant2([4, 5, 6]);
183 
184     value.zeroize();
185 
186     assert!(matches!(&value, Z::Variant2([4, 5, 6])));
187 
188     let mut value = Z::Variant3 {
189         string: String::from("Hello, world!"),
190         vec: vec![1, 2, 3],
191         bytearray: [4, 5, 6],
192         number: 42,
193         boolean: true,
194     };
195 
196     value.zeroize();
197 
198     assert!(matches!(
199         &value,
200         Z::Variant3 { string, vec, bytearray, number, boolean }
201         if string == "Hello, world!" &&
202             vec == &[1, 2, 3] &&
203             bytearray == &[4, 5, 6] &&
204             *number == 42 &&
205             *boolean
206     ));
207 
208     let mut value = Z::Variant4 {
209         string: String::from("Hello, world!"),
210         vec: vec![1, 2, 3],
211         bytearray: [4, 5, 6],
212         number: 42,
213         boolean: true,
214     };
215 
216     value.zeroize();
217 
218     assert!(matches!(
219         &value,
220         Z::Variant4 { string, vec, bytearray, number, boolean }
221         if string.is_empty() &&
222             vec.is_empty() &&
223             bytearray == &[4, 5, 6] &&
224             *number == 0 &&
225             !boolean
226     ));
227 }
228 
229 #[test]
derive_bound()230 fn derive_bound() {
231     trait T: Zeroize {}
232 
233     impl T for u8 {}
234 
235     #[derive(Zeroize)]
236     #[zeroize(bound = "X: T")]
237     struct Z<X>(X);
238 
239     let mut value = Z(5_u8);
240 
241     value.zeroize();
242 
243     assert_eq!(value.0, 0);
244 }
245 
246 #[test]
derive_inherit_zeroize_on_drop()247 fn derive_inherit_zeroize_on_drop() {
248     #[derive(ZeroizeOnDrop)]
249     struct X([u8; 3]);
250 
251     #[derive(ZeroizeOnDrop)]
252     struct Z(X);
253 
254     let mut value = Z(X([1, 2, 3]));
255     unsafe {
256         std::ptr::drop_in_place(&mut value);
257     }
258     assert_eq!(&value.0 .0, &[0, 0, 0])
259 }
260 
261 #[test]
derive_inherit_from_both()262 fn derive_inherit_from_both() {
263     #[derive(Zeroize, ZeroizeOnDrop)]
264     struct X([u8; 3]);
265 
266     #[derive(ZeroizeOnDrop)]
267     struct Z(X);
268 
269     let mut value = Z(X([1, 2, 3]));
270     unsafe {
271         std::ptr::drop_in_place(&mut value);
272     }
273     assert_eq!(&value.0 .0, &[0, 0, 0])
274 }
275 
276 #[test]
derive_inherit_both()277 fn derive_inherit_both() {
278     #[derive(Zeroize, ZeroizeOnDrop)]
279     struct X([u8; 3]);
280 
281     #[derive(Zeroize, ZeroizeOnDrop)]
282     struct Z(X);
283 
284     let mut value = Z(X([1, 2, 3]));
285     unsafe {
286         std::ptr::drop_in_place(&mut value);
287     }
288     assert_eq!(&value.0 .0, &[0, 0, 0])
289 }
290 
291 #[test]
derive_deref()292 fn derive_deref() {
293     struct X([u8; 3]);
294 
295     impl std::ops::Deref for X {
296         type Target = [u8];
297 
298         fn deref(&self) -> &Self::Target {
299             &self.0
300         }
301     }
302 
303     impl std::ops::DerefMut for X {
304         fn deref_mut(&mut self) -> &mut Self::Target {
305             &mut self.0
306         }
307     }
308 
309     #[derive(Zeroize, ZeroizeOnDrop)]
310     struct Z(X);
311 
312     let mut value = Z(X([1, 2, 3]));
313     unsafe {
314         std::ptr::drop_in_place(&mut value);
315     }
316     assert_eq!(&value.0 .0, &[0, 0, 0])
317 }
318 
319 #[test]
320 #[cfg(feature = "alloc")]
derive_zeroize_on_drop_generic()321 fn derive_zeroize_on_drop_generic() {
322     #[derive(ZeroizeOnDrop)]
323     struct Y<T: Zeroize>(Box<T>);
324 
325     #[derive(ZeroizeOnDrop)]
326     struct Z<T: Zeroize>(Vec<T>);
327 }
328