Skip to content

Commit 8b641df

Browse files
committed
Implement ZeroizeOnDrop without Drop
1 parent 4980b4e commit 8b641df

File tree

11 files changed

+303
-53
lines changed

11 files changed

+303
-53
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,12 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [Unreleased]
9+
10+
### Added
11+
- `no_drop` item-level option to `ZeroizeOnDrop` which does not implement
12+
`Drop` but instead only asserts that every field implements `ZeroizeOnDrop`.
13+
814
## [1.4.0] - 2025-05-01
915

1016
### Added

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -238,9 +238,11 @@ If the `zeroize-on-drop` feature is enabled, it implements [`ZeroizeOnDrop`]
238238
and can be implemented without [`Zeroize`], otherwise it only implements
239239
[`Drop`] and requires [`Zeroize`] to be implemented.
240240

241-
[`ZeroizeOnDrop`] has one option:
241+
[`ZeroizeOnDrop`] has two options:
242242
- `crate`: an item-level option which specifies a path to the [`zeroize`]
243243
crate in case of a re-export or rename.
244+
- `no_drop`: an item-level option which will not implement [`Drop`] but instead
245+
only assert that every field implements [`ZeroizeOnDrop`].
244246

245247
```rust
246248
#[derive_where(ZeroizeOnDrop(crate = zeroize_))]

src/attr/item.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -386,6 +386,8 @@ pub enum DeriveTrait {
386386
ZeroizeOnDrop {
387387
/// [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html) path.
388388
crate_: Option<Path>,
389+
/// If `Drop` should be implemented.
390+
no_drop: bool,
389391
},
390392
}
391393

src/input.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -183,11 +183,19 @@ impl<'a> Input<'a> {
183183
{
184184
// `Zeroize(crate = ..)` or `ZeroizeOnDrop(crate = ..)` is used.
185185
if let DeriveTrait::Zeroize { crate_: Some(_) }
186-
| DeriveTrait::ZeroizeOnDrop { crate_: Some(_) } = *trait_
186+
| DeriveTrait::ZeroizeOnDrop {
187+
crate_: Some(_), ..
188+
} = *trait_
187189
{
188190
continue;
189191
}
190192

193+
// `ZeroizeOnDrop(no_drop)` is used.
194+
#[cfg(feature = "zeroize-on-drop")]
195+
if let DeriveTrait::ZeroizeOnDrop { no_drop: true, .. } = *trait_ {
196+
continue;
197+
}
198+
191199
// `Zeroize(fqs)` is used on any field.
192200
if trait_ == Trait::Zeroize && item.any_fqs() {
193201
continue;

src/lib.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -272,9 +272,11 @@
272272
//! and can be implemented without [`Zeroize`], otherwise it only implements
273273
//! [`Drop`] and requires [`Zeroize`] to be implemented.
274274
//!
275-
//! [`ZeroizeOnDrop`] has one option:
275+
//! [`ZeroizeOnDrop`] has two options:
276276
//! - `crate`: an item-level option which specifies a path to the [`zeroize`]
277277
//! crate in case of a re-export or rename.
278+
//! - `no_drop`: an item-level option which will not implement [`Drop`] but
279+
//! instead only assert that every field implements [`ZeroizeOnDrop`].
278280
//!
279281
//! ```
280282
//! # #[cfg(feature = "zeroize-on-drop")]
@@ -642,15 +644,7 @@ fn generate_impl(
642644
let body = generate_body(derive_where, trait_, item, generics);
643645

644646
let ident = item.ident();
645-
let path = trait_.impl_path(trait_);
646-
let mut output = quote! {
647-
#[automatically_derived]
648-
impl #imp #path for #ident #ty
649-
#where_clause
650-
{
651-
#body
652-
}
653-
};
647+
let mut output = trait_.impl_item(trait_, imp, ident, ty, &where_clause, body);
654648

655649
if let Some((path, body)) = trait_.additional_impl(trait_) {
656650
output.extend(quote! {

src/test/zeroize.rs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -302,3 +302,47 @@ fn enum_skip_drop() -> Result<()> {
302302
},
303303
)
304304
}
305+
306+
#[test]
307+
#[cfg(feature = "zeroize-on-drop")]
308+
fn no_drop() -> Result<()> {
309+
test_derive(
310+
quote! {
311+
#[derive_where(ZeroizeOnDrop(no_drop); T)]
312+
struct Test<T, U>(T, std::marker::PhantomData<U>);
313+
},
314+
quote! {
315+
const _: () = {
316+
trait DeriveWhereAssertZeroizeOnDrop {
317+
fn assert(&mut self);
318+
}
319+
320+
impl<T, U> DeriveWhereAssertZeroizeOnDrop for Test <T, U>
321+
where T: ::zeroize::ZeroizeOnDrop
322+
{
323+
fn assert(&mut self) {
324+
trait AssertZeroizeOnDrop {
325+
fn __derive_where_zeroize_on_drop(&mut self);
326+
}
327+
328+
impl<T: ::zeroize::ZeroizeOnDrop + ?::core::marker::Sized> AssertZeroizeOnDrop for T {
329+
fn __derive_where_zeroize_on_drop(&mut self) {}
330+
}
331+
332+
match self {
333+
Test (ref mut __field_0, ref mut __field_1) => {
334+
__field_0.__derive_where_zeroize_on_drop();
335+
__field_1.__derive_where_zeroize_on_drop();
336+
}
337+
}
338+
}
339+
}
340+
};
341+
342+
#[automatically_derived]
343+
impl<T, U> ::zeroize::ZeroizeOnDrop for Test<T, U>
344+
where T: ::zeroize::ZeroizeOnDrop
345+
{ }
346+
},
347+
)
348+
}

src/trait_.rs

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,14 @@ mod zeroize;
1515
#[cfg(feature = "zeroize")]
1616
mod zeroize_on_drop;
1717

18+
use std::borrow::Cow;
19+
1820
use proc_macro2::{Span, TokenStream};
19-
use syn::{punctuated::Punctuated, spanned::Spanned, Meta, Path, Result, Token, TypeParamBound};
21+
use quote::quote;
22+
use syn::{
23+
punctuated::Punctuated, spanned::Spanned, Ident, ImplGenerics, Meta, Path, Result, Token,
24+
TypeGenerics, TypeParamBound, WhereClause,
25+
};
2026

2127
use crate::{Data, DeriveTrait, DeriveWhere, Error, Item, SplitGenerics};
2228

@@ -127,8 +133,17 @@ impl TraitImpl for Trait {
127133
self.implementation().additional_impl(trait_)
128134
}
129135

130-
fn impl_path(&self, trait_: &DeriveTrait) -> Path {
131-
self.implementation().impl_path(trait_)
136+
fn impl_item(
137+
&self,
138+
trait_: &DeriveTrait,
139+
imp: &ImplGenerics<'_>,
140+
ident: &Ident,
141+
ty: &TypeGenerics<'_>,
142+
where_clause: &Option<Cow<'_, WhereClause>>,
143+
body: TokenStream,
144+
) -> TokenStream {
145+
self.implementation()
146+
.impl_item(trait_, imp, ident, ty, where_clause, body)
132147
}
133148

134149
fn build_signature(
@@ -189,8 +204,25 @@ pub trait TraitImpl {
189204

190205
/// Trait to implement. Only used for [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html)
191206
/// because it implements [`Drop`] and not itself.
192-
fn impl_path(&self, trait_: &DeriveTrait) -> Path {
193-
trait_.path()
207+
fn impl_item(
208+
&self,
209+
trait_: &DeriveTrait,
210+
imp: &ImplGenerics<'_>,
211+
ident: &Ident,
212+
ty: &TypeGenerics<'_>,
213+
where_clause: &Option<Cow<'_, WhereClause>>,
214+
body: TokenStream,
215+
) -> TokenStream {
216+
let path = trait_.path();
217+
218+
quote! {
219+
#[automatically_derived]
220+
impl #imp #path for #ident #ty
221+
#where_clause
222+
{
223+
#body
224+
}
225+
}
194226
}
195227

196228
/// Build method signature for this [`Trait`].

0 commit comments

Comments
 (0)