From e8007cb86de7a51a5904da2f5895dab8271440a8 Mon Sep 17 00:00:00 2001 From: Scott Sanderson Date: Tue, 30 Dec 2025 12:08:29 -0500 Subject: [PATCH] zeroize: support unsized types in Zeroizing 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>` and `Zeroizing>`. --- zeroize/src/lib.rs | 18 ++++---- zeroize/tests/zeroize.rs | 89 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 98 insertions(+), 9 deletions(-) diff --git a/zeroize/src/lib.rs b/zeroize/src/lib.rs index e2662c2e..0a452163 100644 --- a/zeroize/src/lib.rs +++ b/zeroize/src/lib.rs @@ -626,7 +626,7 @@ impl Zeroize for CString { /// guaranteed to have the same physical representation as the underlying type. #[derive(Debug, Default, Eq, PartialEq)] #[repr(transparent)] -pub struct Zeroizing(Z); +pub struct Zeroizing(Z); impl Zeroizing where @@ -665,7 +665,7 @@ where impl ops::Deref for Zeroizing where - Z: Zeroize, + Z: Zeroize + ?Sized, { type Target = Z; @@ -677,7 +677,7 @@ where impl ops::DerefMut for Zeroizing where - Z: Zeroize, + Z: Zeroize + ?Sized, { #[inline(always)] fn deref_mut(&mut self) -> &mut Z { @@ -688,7 +688,7 @@ where impl AsRef for Zeroizing where T: ?Sized, - Z: AsRef + Zeroize, + Z: AsRef + Zeroize + ?Sized, { #[inline(always)] fn as_ref(&self) -> &T { @@ -699,7 +699,7 @@ where impl AsMut for Zeroizing where T: ?Sized, - Z: AsMut + Zeroize, + Z: AsMut + Zeroize + ?Sized, { #[inline(always)] fn as_mut(&mut self) -> &mut T { @@ -709,18 +709,18 @@ where impl Zeroize for Zeroizing where - Z: Zeroize, + Z: Zeroize + ?Sized, { fn zeroize(&mut self) { self.0.zeroize(); } } -impl ZeroizeOnDrop for Zeroizing where Z: Zeroize {} +impl ZeroizeOnDrop for Zeroizing where Z: Zeroize + ?Sized {} impl Drop for Zeroizing where - Z: Zeroize, + Z: Zeroize + ?Sized, { fn drop(&mut self) { self.0.zeroize() @@ -730,7 +730,7 @@ where #[cfg(feature = "serde")] impl serde::Serialize for Zeroizing where - Z: Zeroize + serde::Serialize, + Z: Zeroize + serde::Serialize + ?Sized, { #[inline(always)] fn serialize(&self, serializer: S) -> Result diff --git a/zeroize/tests/zeroize.rs b/zeroize/tests/zeroize.rs index afc824e0..f462a96f 100644 --- a/zeroize/tests/zeroize.rs +++ b/zeroize/tests/zeroize.rs @@ -4,6 +4,7 @@ use std::{ marker::{PhantomData, PhantomPinned}, mem::{MaybeUninit, size_of}, num::*, + sync::Arc, }; use zeroize::*; @@ -208,3 +209,91 @@ fn asref() { let _asmut: &mut [u8] = buffer.as_mut(); let _asref: &[u8] = buffer.as_ref(); } + +#[cfg(feature = "alloc")] +#[test] +fn box_unsized_zeroizing() { + let mut b: Box> = Box::new(Zeroizing::new([1, 2, 3, 4])); + { + let s: &[u8] = &b; + assert_eq!(s, &[1, 2, 3, 4]); + + let s: &[u8] = b.as_ref(); + assert_eq!(s, &[1, 2, 3, 4]); + + let s: &mut [u8] = b.as_mut(); + assert_eq!(s, &[1, 2, 3, 4]); + } + + unsafe { + core::ptr::drop_in_place(&mut *b); + } + + let s: &[u8] = &b; + assert_eq!(s, &[0, 0, 0, 0]); +} + +#[cfg(feature = "alloc")] +#[test] +fn arc_unsized_zeroizing() { + let mut arc: Arc> = Arc::new(Zeroizing::new([1, 2, 3, 4])); + { + let s: &[u8] = &arc; + assert_eq!(s, &[1, 2, 3, 4]); + + let s: &[u8] = arc.as_ref(); + assert_eq!(s, &[1, 2, 3, 4]); + } + + unsafe { + let inner = Arc::get_mut(&mut arc).unwrap(); + core::ptr::drop_in_place(inner); + } + + let s: &[u8] = &arc; + assert_eq!(s, &[0, 0, 0, 0]); +} + +// This is a weird way to use zeroizing, but it's technically allowed b/c +// unsized types can be stored inside Zeroizing, so make sure it works as +// expected. +#[test] +fn zeroizing_dyn_trait() { + trait TestTrait: Zeroize { + fn data(&self) -> &[u8]; + } + + struct TestStruct { + data: [u8; 4], + } + + impl Zeroize for TestStruct { + fn zeroize(&mut self) { + self.data.zeroize(); + } + } + + impl Drop for TestStruct { + fn drop(&mut self) { + self.zeroize(); + } + } + + impl TestTrait for TestStruct { + fn data(&self) -> &[u8] { + &self.data + } + } + + let mut b: Box> = + Box::new(Zeroizing::new(TestStruct { data: [1, 2, 3, 4] })); + + unsafe { + core::ptr::drop_in_place(&mut *b); + } + + let inner: &Zeroizing = &b; + let inner: &dyn TestTrait = std::ops::Deref::deref(inner); + + assert_eq!(inner.data(), &[0, 0, 0, 0]); +}