Skip to content

Commit

Permalink
revised docs some more
Browse files Browse the repository at this point in the history
  • Loading branch information
nstilt1 committed Jan 24, 2024
1 parent dc91cc2 commit 92d89e3
Showing 1 changed file with 32 additions and 67 deletions.
99 changes: 32 additions & 67 deletions zeroize/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -796,8 +796,8 @@ unsafe fn volatile_set<T: Copy + Sized>(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<X>
Expand All @@ -807,89 +807,54 @@ unsafe fn volatile_set<T: Copy + Sized>(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<T>
/// - Box<T>
/// - Vec<T>
/// - HashMap<T1, T2>
/// - 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<u8>,
/// smart_ptr_2: Box<u8>,
/// smart_ptr_3: Arc<u8>,
/// hashmap: HashMap<u32, u32>,
/// 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<T: Sized>(data: *mut T) {
let size = mem::size_of::<T>();
pub unsafe fn zeroize_flat_type<F: Sized>(data: *mut F) {
let size = mem::size_of::<F>();
// Safety:
//
// This is safe because `mem::size_of<T>()` returns the exact size of the object in memory, and
Expand Down

0 comments on commit 92d89e3

Please sign in to comment.