From 92d89e37420b9967b8bd4d9354bf098fc147a044 Mon Sep 17 00:00:00 2001 From: Noah Stiltner Date: Wed, 24 Jan 2024 17:20:23 -0600 Subject: [PATCH] revised docs some more --- zeroize/src/lib.rs | 99 +++++++++++++++------------------------------- 1 file changed, 32 insertions(+), 67 deletions(-) diff --git a/zeroize/src/lib.rs b/zeroize/src/lib.rs index ad67b725..bf139147 100644 --- a/zeroize/src/lib.rs +++ b/zeroize/src/lib.rs @@ -796,8 +796,8 @@ unsafe fn volatile_set(dst: *mut T, src: T, count: usize) { } /// Zeroizes a flat type/struct. Only zeroizes the values that it owns, and it does not work on -/// dynamically sized values or trait objects. Do not use this function on a type that already -/// implements `ZeroizeOnDrop`. +/// dynamically sized values or trait objects. It would be inefficient to use this function on a +/// type that already implements `ZeroizeOnDrop`. /// /// # Safety /// - The type must not contain references to outside data or dynamically sized data, such as Vec @@ -807,89 +807,54 @@ unsafe fn volatile_set(dst: *mut T, src: T, count: usize) { /// - The bit pattern of all zeroes must be valid for the data being zeroized. This may not be true for /// enums and pointers. /// +/// # Incompatible data types +/// Some data types that cannot be safely zeroized using `zeroize_flat_type` include, but are not +/// limited to: +/// - pointers such as +/// - *const u8 +/// - *mut u8 +/// - references such as +/// - &T +/// - &mut T +/// - smart pointers and collections +/// - Arc +/// - Box +/// - Vec +/// - HashMap +/// - String +/// +/// Some data types that may be invalid after calling `zeroize_flat_type`: +/// - enums +/// /// # Examples -/// Safe usage for a simple struct: +/// Safe usage for a struct containing strictly flat data: /// ``` /// use zeroize::{ZeroizeOnDrop, zeroize_flat_type}; /// -/// struct DataToZeroize(u64); -/// -/// struct MoreDataToZeroize { +/// struct DataToZeroize { /// flat_data_1: [u8; 32], -/// flat_data_2: DataToZeroize, +/// flat_data_2: SomeMoreFlatData, /// } /// -/// impl Drop for MoreDataToZeroize { +/// struct SomeMoreFlatData(u64); +/// +/// impl Drop for DataToZeroize { /// fn drop(&mut self) { /// unsafe { zeroize_flat_type(self as *mut Self) } /// } /// } -/// impl ZeroizeOnDrop for MoreDataToZeroize {} +/// impl ZeroizeOnDrop for DatatoZeroize {} /// -/// let mut data = MoreDataToZeroize { +/// let mut data = DataToZerioze { /// flat_data_1: [3u8; 32], -/// flat_data_2: DataToZeroize(123u64) +/// flat_data_2: SomeMoreFlatData(123u64) /// }; /// /// // data gets zeroized when dropped /// ``` -/// ## Unsafe examples -/// Below is an unsafe example. It is not comprehensive, but if the data you want to zeroize -/// contains any of the following types, consider using `Zeroize` instead of `zeroize_flat_type`. -/// ``` -/// use std::boxed::Box; -/// use std::collections::HashMap; -/// use std::sync::Arc; -/// use std::vec::Vec; -/// -/// struct UnsafeExample<'a> { -/// // zeroizing pointers will create a null pointer, which could lead to dereferencing -/// // null pointers -/// ptr: *const u8, -/// ptr_mut: *mut u8, -/// -/// // references are non-nullable and should point to valid data -/// reference: &'a u8, -/// reference_mut: &'a mut u8, -/// -/// // smart pointers are designed to manage ownership and deallocation of heap memory. -/// // zeroizing them can mess up this management and result in memory leaks or double frees. -/// smart_ptr_1: Vec, -/// smart_ptr_2: Box, -/// smart_ptr_3: Arc, -/// hashmap: HashMap, -/// string: String -/// } -/// -/// // calling `zeroize_flat_type()` on this struct could be unsafe -/// ``` -/// -/// The below example shows what happens when `zeroize_flat_type` is ran on a type containing a -/// smart pointer. -/// ```no_run -/// use zeroize::zeroize_flat_type; -/// -/// struct UnsafeExample(String); -/// -/// let mut data = UnsafeExample(String::from("take care when zeroizing with zeroize_flat_type()")); -/// -/// // save the original pointer to determine if the data is still in memory after zeroizing -/// let original_ptr = data.0.as_ptr(); -/// -/// unsafe { zeroize_flat_type(&mut data as *mut UnsafeExample) } -/// -/// // the String's metadata was overwritten (such as the pointer to the heap, length, capacity) -/// assert_eq!(data.0.as_ptr().is_null(), true); -/// assert_eq!(data.0.len(), 0); -/// assert_eq!(data.0.capacity(), 0); -/// -/// // the original data still lives on the heap, possibly resulting in a little memory leak -/// let memory_inspection = unsafe { core::slice::from_raw_parts(original_ptr, 49) }; -/// assert_eq!(memory_inspection, b"take care when zeroizing with zeroize_flat_type()"); -/// ``` #[inline(always)] -pub unsafe fn zeroize_flat_type(data: *mut T) { - let size = mem::size_of::(); +pub unsafe fn zeroize_flat_type(data: *mut F) { + let size = mem::size_of::(); // Safety: // // This is safe because `mem::size_of()` returns the exact size of the object in memory, and