Skip to content

Commit f5df3cf

Browse files
authored
zeroize: add unsafe zeroize_flat_type function (#1045)
1 parent a0b8b38 commit f5df3cf

File tree

1 file changed

+68
-0
lines changed

1 file changed

+68
-0
lines changed

zeroize/src/lib.rs

+68
Original file line numberDiff line numberDiff line change
@@ -795,6 +795,74 @@ unsafe fn volatile_set<T: Copy + Sized>(dst: *mut T, src: T, count: usize) {
795795
}
796796
}
797797

798+
/// Zeroizes a flat type/struct. Only zeroizes the values that it owns, and it does not work on
799+
/// dynamically sized values or trait objects. It would be inefficient to use this function on a
800+
/// type that already implements `ZeroizeOnDrop`.
801+
///
802+
/// # Safety
803+
/// - The type must not contain references to outside data or dynamically sized data, such as Vec<X>
804+
/// or String<X>.
805+
/// - This function can invalidate the type if it is used after this function is called on it. It is
806+
/// advisable to call this function in `impl Drop`.
807+
/// - The bit pattern of all zeroes must be valid for the data being zeroized. This may not be true for
808+
/// enums and pointers.
809+
///
810+
/// # Incompatible data types
811+
/// Some data types that cannot be safely zeroized using `zeroize_flat_type` include, but are not
812+
/// limited to:
813+
/// - pointers such as
814+
/// - *const u8
815+
/// - *mut u8
816+
/// - references such as
817+
/// - &T
818+
/// - &mut T
819+
/// - smart pointers and collections
820+
/// - Arc<T>
821+
/// - Box<T>
822+
/// - Vec<T>
823+
/// - HashMap<T1, T2>
824+
/// - String
825+
///
826+
/// Some data types that may be invalid after calling `zeroize_flat_type`:
827+
/// - enums
828+
///
829+
/// # Examples
830+
/// Safe usage for a struct containing strictly flat data:
831+
/// ```
832+
/// use zeroize::{ZeroizeOnDrop, zeroize_flat_type};
833+
///
834+
/// struct DataToZeroize {
835+
/// flat_data_1: [u8; 32],
836+
/// flat_data_2: SomeMoreFlatData,
837+
/// }
838+
///
839+
/// struct SomeMoreFlatData(u64);
840+
///
841+
/// impl Drop for DataToZeroize {
842+
/// fn drop(&mut self) {
843+
/// unsafe { zeroize_flat_type(self as *mut Self) }
844+
/// }
845+
/// }
846+
/// impl ZeroizeOnDrop for DataToZeroize {}
847+
///
848+
/// let mut data = DataToZeroize {
849+
/// flat_data_1: [3u8; 32],
850+
/// flat_data_2: SomeMoreFlatData(123u64)
851+
/// };
852+
///
853+
/// // data gets zeroized when dropped
854+
/// ```
855+
#[inline(always)]
856+
pub unsafe fn zeroize_flat_type<F: Sized>(data: *mut F) {
857+
let size = mem::size_of::<F>();
858+
// Safety:
859+
//
860+
// This is safe because `mem::size_of<T>()` returns the exact size of the object in memory, and
861+
// `data_ptr` points directly to the first byte of the data.
862+
volatile_set(data as *mut u8, 0, size);
863+
atomic_fence()
864+
}
865+
798866
/// Internal module used as support for `AssertZeroizeOnDrop`.
799867
#[doc(hidden)]
800868
pub mod __internal {

0 commit comments

Comments
 (0)