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