From 600130755e972f47f2266e0c6eeeceaf0b5e11ce Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 5 Jun 2023 16:16:25 -0700 Subject: [PATCH 1/4] Add functions for writing zeroed bytes to `&mut impl Zeroable` and `&mut [impl Zeroable]` --- src/lib.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/lib.rs b/src/lib.rs index 7ee1f903..be59961a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -398,3 +398,33 @@ pub fn try_cast_slice_mut< ) -> Result<&mut [B], PodCastError> { unsafe { internal::try_cast_slice_mut(a) } } + +/// Fill all bytes of `target` with zeroes (see [`Zeroable`]). +/// +/// This is similar to `*target = Zeroable::zeroed()`, but guarantees that any +/// padding bytes in `target` are zeroed as well. +/// +/// See also [`fill_zero`], if you have a slice rather than a single value. +#[inline] +pub fn write_zero(target: &mut T) { + unsafe { + core::ptr::write_bytes( + target as *mut T as *mut u8, + 0u8, + core::mem::size_of::(), + ) + } +} + +/// Fill all bytes of `slice` with zeroes (see [`Zeroable`]). +/// +/// This is similar to `slice.fill(Zeroable::zeroed())`, but guarantees that any +/// padding bytes in `slice` are zeroed as well. +/// +/// See also [`write_zero`], which zeroes all bytes of a single value rather +/// than a slice. +#[inline] +pub fn fill_zero(slice: &mut [T]) { + let len = core::mem::size_of_val::<[T]>(slice); + unsafe { core::ptr::write_bytes(slice.as_mut_ptr() as *mut u8, 0u8, len) } +} From c58baab2b3cb0c53264a314f994b397edadc6d60 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Mon, 5 Jun 2023 16:47:20 -0700 Subject: [PATCH 2/4] Support `T: !Copy` in `fill_zero`/`write_zero` --- src/lib.rs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index be59961a..25d72df8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -406,8 +406,9 @@ pub fn try_cast_slice_mut< /// /// See also [`fill_zero`], if you have a slice rather than a single value. #[inline] -pub fn write_zero(target: &mut T) { +pub fn write_zero(target: &mut T) { unsafe { + core::ptr::drop_in_place(target); core::ptr::write_bytes( target as *mut T as *mut u8, 0u8, @@ -424,7 +425,14 @@ pub fn write_zero(target: &mut T) { /// See also [`write_zero`], which zeroes all bytes of a single value rather /// than a slice. #[inline] -pub fn fill_zero(slice: &mut [T]) { - let len = core::mem::size_of_val::<[T]>(slice); - unsafe { core::ptr::write_bytes(slice.as_mut_ptr() as *mut u8, 0u8, len) } +pub fn fill_zero(slice: &mut [T]) { + if core::mem::needs_drop::() { + // If `T` needs to be dropped then we have to do this one item at a time, in + // case one of the intermediate drops does a panic. + slice.iter_mut().for_each(write_zero); + } else { + // Otherwise we can be really fast and just fill everthing with zeros. + let len = core::mem::size_of_val::<[T]>(slice); + unsafe { core::ptr::write_bytes(slice.as_mut_ptr() as *mut u8, 0u8, len) } + } } From 8177bae72537f4232ad4190ab7315a27764027e9 Mon Sep 17 00:00:00 2001 From: Thom Chiovoloni Date: Fri, 7 Jul 2023 18:52:29 -0700 Subject: [PATCH 3/4] Zero bytes in the drop guard for write_zero --- src/lib.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 25d72df8..5c3a67c2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -407,13 +407,23 @@ pub fn try_cast_slice_mut< /// See also [`fill_zero`], if you have a slice rather than a single value. #[inline] pub fn write_zero(target: &mut T) { + struct EnsureZeroWrite(*mut T); + impl Drop for EnsureZeroWrite { + #[inline(always)] + fn drop(&mut self) { + unsafe { + core::ptr::write_bytes( + self.0.cast::(), + 0u8, + core::mem::size_of::(), + ); + } + } + } unsafe { - core::ptr::drop_in_place(target); - core::ptr::write_bytes( - target as *mut T as *mut u8, - 0u8, - core::mem::size_of::(), - ) + let guard = EnsureZeroWrite(target); + core::ptr::drop_in_place(guard.0); + drop(guard); } } From 9fffad320848e7f3d8679b102b699acf9e170a07 Mon Sep 17 00:00:00 2001 From: Lokathor Date: Tue, 5 Sep 2023 13:42:09 -0600 Subject: [PATCH 4/4] Update src/lib.rs Co-authored-by: Alphyr <47725341+a1phyr@users.noreply.github.com> --- src/lib.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index 5c3a67c2..91f6fd72 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -412,11 +412,7 @@ pub fn write_zero(target: &mut T) { #[inline(always)] fn drop(&mut self) { unsafe { - core::ptr::write_bytes( - self.0.cast::(), - 0u8, - core::mem::size_of::(), - ); + core::ptr::write_bytes(self.0, 0u8, 1); } } }