Skip to content

Commit 5c46037

Browse files
authored
zeroize: support unsized types in Zeroizing (#1318)
This commit adds `?Sized` to the generic bounds on Zeroizing and many of its trait implementations. This makes it possible to form and use types like `Zeroizing<Box<[u8]>>` and `Zeroizing<Arc<[u8]>>`. This also allows forming more exotic types like `Zeroizing<dyn SomeTrait>` where `SomeTrait: Zeroize`. I've included a test for that case to ensure that nothing unexpected breaks if it's used in that way, but that usage is probably not to be recommended. See #1256 for more details.
1 parent e264242 commit 5c46037

2 files changed

Lines changed: 98 additions & 9 deletions

File tree

zeroize/src/lib.rs

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -626,7 +626,7 @@ impl Zeroize for CString {
626626
/// guaranteed to have the same physical representation as the underlying type.
627627
#[derive(Debug, Default, Eq, PartialEq)]
628628
#[repr(transparent)]
629-
pub struct Zeroizing<Z: Zeroize>(Z);
629+
pub struct Zeroizing<Z: Zeroize + ?Sized>(Z);
630630

631631
impl<Z> Zeroizing<Z>
632632
where
@@ -665,7 +665,7 @@ where
665665

666666
impl<Z> ops::Deref for Zeroizing<Z>
667667
where
668-
Z: Zeroize,
668+
Z: Zeroize + ?Sized,
669669
{
670670
type Target = Z;
671671

@@ -677,7 +677,7 @@ where
677677

678678
impl<Z> ops::DerefMut for Zeroizing<Z>
679679
where
680-
Z: Zeroize,
680+
Z: Zeroize + ?Sized,
681681
{
682682
#[inline(always)]
683683
fn deref_mut(&mut self) -> &mut Z {
@@ -688,7 +688,7 @@ where
688688
impl<T, Z> AsRef<T> for Zeroizing<Z>
689689
where
690690
T: ?Sized,
691-
Z: AsRef<T> + Zeroize,
691+
Z: AsRef<T> + Zeroize + ?Sized,
692692
{
693693
#[inline(always)]
694694
fn as_ref(&self) -> &T {
@@ -699,7 +699,7 @@ where
699699
impl<T, Z> AsMut<T> for Zeroizing<Z>
700700
where
701701
T: ?Sized,
702-
Z: AsMut<T> + Zeroize,
702+
Z: AsMut<T> + Zeroize + ?Sized,
703703
{
704704
#[inline(always)]
705705
fn as_mut(&mut self) -> &mut T {
@@ -709,18 +709,18 @@ where
709709

710710
impl<Z> Zeroize for Zeroizing<Z>
711711
where
712-
Z: Zeroize,
712+
Z: Zeroize + ?Sized,
713713
{
714714
fn zeroize(&mut self) {
715715
self.0.zeroize();
716716
}
717717
}
718718

719-
impl<Z> ZeroizeOnDrop for Zeroizing<Z> where Z: Zeroize {}
719+
impl<Z> ZeroizeOnDrop for Zeroizing<Z> where Z: Zeroize + ?Sized {}
720720

721721
impl<Z> Drop for Zeroizing<Z>
722722
where
723-
Z: Zeroize,
723+
Z: Zeroize + ?Sized,
724724
{
725725
fn drop(&mut self) {
726726
self.0.zeroize()
@@ -730,7 +730,7 @@ where
730730
#[cfg(feature = "serde")]
731731
impl<Z> serde::Serialize for Zeroizing<Z>
732732
where
733-
Z: Zeroize + serde::Serialize,
733+
Z: Zeroize + serde::Serialize + ?Sized,
734734
{
735735
#[inline(always)]
736736
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>

zeroize/tests/zeroize.rs

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ use std::{
44
marker::{PhantomData, PhantomPinned},
55
mem::{MaybeUninit, size_of},
66
num::*,
7+
sync::Arc,
78
};
89
use zeroize::*;
910

@@ -208,3 +209,91 @@ fn asref() {
208209
let _asmut: &mut [u8] = buffer.as_mut();
209210
let _asref: &[u8] = buffer.as_ref();
210211
}
212+
213+
#[cfg(feature = "alloc")]
214+
#[test]
215+
fn box_unsized_zeroizing() {
216+
let mut b: Box<Zeroizing<[u8]>> = Box::new(Zeroizing::new([1, 2, 3, 4]));
217+
{
218+
let s: &[u8] = &b;
219+
assert_eq!(s, &[1, 2, 3, 4]);
220+
221+
let s: &[u8] = b.as_ref();
222+
assert_eq!(s, &[1, 2, 3, 4]);
223+
224+
let s: &mut [u8] = b.as_mut();
225+
assert_eq!(s, &[1, 2, 3, 4]);
226+
}
227+
228+
unsafe {
229+
core::ptr::drop_in_place(&mut *b);
230+
}
231+
232+
let s: &[u8] = &b;
233+
assert_eq!(s, &[0, 0, 0, 0]);
234+
}
235+
236+
#[cfg(feature = "alloc")]
237+
#[test]
238+
fn arc_unsized_zeroizing() {
239+
let mut arc: Arc<Zeroizing<[u8]>> = Arc::new(Zeroizing::new([1, 2, 3, 4]));
240+
{
241+
let s: &[u8] = &arc;
242+
assert_eq!(s, &[1, 2, 3, 4]);
243+
244+
let s: &[u8] = arc.as_ref();
245+
assert_eq!(s, &[1, 2, 3, 4]);
246+
}
247+
248+
unsafe {
249+
let inner = Arc::get_mut(&mut arc).unwrap();
250+
core::ptr::drop_in_place(inner);
251+
}
252+
253+
let s: &[u8] = &arc;
254+
assert_eq!(s, &[0, 0, 0, 0]);
255+
}
256+
257+
// This is a weird way to use zeroizing, but it's technically allowed b/c
258+
// unsized types can be stored inside Zeroizing, so make sure it works as
259+
// expected.
260+
#[test]
261+
fn zeroizing_dyn_trait() {
262+
trait TestTrait: Zeroize {
263+
fn data(&self) -> &[u8];
264+
}
265+
266+
struct TestStruct {
267+
data: [u8; 4],
268+
}
269+
270+
impl Zeroize for TestStruct {
271+
fn zeroize(&mut self) {
272+
self.data.zeroize();
273+
}
274+
}
275+
276+
impl Drop for TestStruct {
277+
fn drop(&mut self) {
278+
self.zeroize();
279+
}
280+
}
281+
282+
impl TestTrait for TestStruct {
283+
fn data(&self) -> &[u8] {
284+
&self.data
285+
}
286+
}
287+
288+
let mut b: Box<Zeroizing<dyn TestTrait>> =
289+
Box::new(Zeroizing::new(TestStruct { data: [1, 2, 3, 4] }));
290+
291+
unsafe {
292+
core::ptr::drop_in_place(&mut *b);
293+
}
294+
295+
let inner: &Zeroizing<dyn TestTrait> = &b;
296+
let inner: &dyn TestTrait = std::ops::Deref::deref(inner);
297+
298+
assert_eq!(inner.data(), &[0, 0, 0, 0]);
299+
}

0 commit comments

Comments
 (0)