diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index ccbf423..56fdb0f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -22,12 +22,13 @@ jobs: experimental: false - rust: stable features: + bench: true experimental: false - rust: beta features: serde experimental: false - rust: nightly - features: serde + features: serde, zeroize experimental: false steps: @@ -57,4 +58,4 @@ jobs: rustup override set nightly cargo miri setup - name: Test with Miri - run: cargo miri test + run: cargo miri test --all-features diff --git a/Cargo.toml b/Cargo.toml index f92b4f9..98f1684 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,11 @@ version = "1.0" optional = true default-features = false +[dependencies.zeroize] +version = "1.4" +optional = true +default-features = false + [dev-dependencies.serde_test] version = "1.0" diff --git a/src/array_string.rs b/src/array_string.rs index 864daea..90cfc09 100644 --- a/src/array_string.rs +++ b/src/array_string.rs @@ -647,3 +647,27 @@ impl<'a, const CAP: usize> TryFrom> for ArrayString Ok(v) } } + +#[cfg(feature = "zeroize")] +/// "Best efforts" zeroing of the `ArrayString`'s buffer when the `zeroize` feature is enabled. +/// +/// The length is set to 0, and the buffer is dropped and zeroized. +/// Cannot ensure that previous moves of the `ArrayString` did not leave values on the stack. +/// +/// ``` +/// use arrayvec::ArrayString; +/// use zeroize::Zeroize; +/// let mut string = ArrayString::<6>::from("foobar").unwrap(); +/// string.zeroize(); +/// assert_eq!(string.len(), 0); +/// unsafe { string.set_len(string.capacity()) }; +/// assert_eq!(&*string, "\0\0\0\0\0\0"); +/// ``` +impl zeroize::Zeroize for ArrayString { + fn zeroize(&mut self) { + // There are no elements to drop + self.clear(); + // Zeroize the backing array. + self.xs.zeroize(); + } +} diff --git a/src/arrayvec.rs b/src/arrayvec.rs index f5b89e8..37e151a 100644 --- a/src/arrayvec.rs +++ b/src/arrayvec.rs @@ -848,6 +848,32 @@ impl IntoIterator for ArrayVec { } +#[cfg(feature = "zeroize")] +/// "Best efforts" zeroing of the `ArrayVec`'s buffer when the `zeroize` feature is enabled. +/// +/// The length is set to 0, and the buffer is dropped and zeroized. +/// Cannot ensure that previous moves of the `ArrayVec` did not leave values on the stack. +/// +/// ``` +/// use arrayvec::ArrayVec; +/// use zeroize::Zeroize; +/// let mut array = ArrayVec::from([1, 2, 3]); +/// array.zeroize(); +/// assert_eq!(array.len(), 0); +/// let data = unsafe { core::slice::from_raw_parts(array.as_ptr(), array.capacity()) }; +/// assert_eq!(data, [0, 0, 0]); +/// ``` +impl zeroize::Zeroize for ArrayVec { + fn zeroize(&mut self) { + // Zeroize all the contained elements. + self.iter_mut().zeroize(); + // Drop all the elements and set the length to 0. + self.clear(); + // Zeroize the backing array. + self.xs.zeroize(); + } +} + /// By-value iterator for `ArrayVec`. pub struct IntoIter { index: usize,