Skip to content

Implement ZeroizeOnDrop #32

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 9, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,15 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [Unreleased]
### Added
- Support `ZeroizeOnDrop`.

### Removed
- **Breaking Change**: Remove support for `Zeroize(drop)`.

## [1.0.0-rc.1] - 2021-12-08
### Added
- Initial release.

[Unreleased]: https://github.com/ModProg/derive-where/compare/v1.0.0-rc.1...HEAD
[1.0.0-rc.1]: https://github.com/ModProg/derive-where/releases/tag/v1.0.0-rc.1
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,9 @@ syn = { version = "1", default-features = false, features = [
[dev-dependencies]
syn = { version = "1", default-features = false, features = ["extra-traits"] }

[patch.crates-io]
zeroize = { git = "https://github.com/khonsulabs/utils", branch = "zeroize-on-drop-auto-deref" }

[[test]]
name = "util"
path = "tests/util.rs"
Expand Down
26 changes: 20 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ enum Example<T> {

With a `skip` or `skip_inner` attribute fields can be skipped for traits
that allow it, which are: [`Debug`], [`Hash`], [`Ord`](https://doc.rust-lang.org/core/cmp/trait.Ord.html), [`PartialOrd`](https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html),
[`PartialEq`](https://doc.rust-lang.org/core/cmp/trait.PartialEq.html) and [`Zeroize`].
[`PartialEq`](https://doc.rust-lang.org/core/cmp/trait.PartialEq.html), [`Zeroize`] and [`ZeroizeOnDrop`].

```rust
#[derive(DeriveWhere)]
Expand Down Expand Up @@ -148,18 +148,16 @@ assert_ne!(

### `Zeroize` options

[`Zeroize`] has three options:
[`Zeroize`] has two options:
- `crate`: an item-level option which specifies a path to the `zeroize`
crate in case of a re-export or rename.
- `drop`: an item-level option which implements [`Drop`](https://doc.rust-lang.org/core/ops/trait.Drop.html) and uses
[`Zeroize`] to erase all data from memory.
- `fqs`: a field -level option which will use fully-qualified-syntax instead
of calling the [`zeroize`][`method@zeroize`] method on `self` directly.
This is to avoid ambiguity between another method also called `zeroize`.

```rust
#[derive(DeriveWhere)]
#[derive_where(Zeroize(crate = "zeroize_", drop))]
#[derive_where(Zeroize(crate = "zeroize_"))]
struct Example(#[derive_where(Zeroize(fqs))] i32);

impl Example {
Expand All @@ -181,6 +179,20 @@ Zeroize::zeroize(&mut test);
assert_eq!(test.0, 0);
```

### `ZeroizeOnDrop` options

[`ZeroizeOnDrop`] has one option:
- `crate`: an item-level option which specifies a path to the `zeroize`
crate in case of a re-export or rename.

```
#[derive(DeriveWhere)]
#[derive_where(ZeroizeOnDrop(crate = "zeroize_"))]
struct Example(i32);

assert!(core::mem::needs_drop::<Example>());
```

### Supported traits

The following traits can be derived with derive-where:
Expand All @@ -194,6 +206,7 @@ The following traits can be derived with derive-where:
- [`PartialEq`](https://doc.rust-lang.org/core/cmp/trait.PartialEq.html)
- [`PartialOrd`](https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html)
- [`Zeroize`]: Only available with the `zeroize` crate feature.
- [`ZeroizeOnDrop`]: Only available with the `zeroize` crate feature.

### Supported items

Expand All @@ -220,7 +233,7 @@ Unions only support [`Clone`](https://doc.rust-lang.org/core/clone/trait.Clone.h
replaces all cases of [`core::hint::unreachable_unchecked`](https://doc.rust-lang.org/core/hint/fn.unreachable_unchecked.html) in [`Ord`](https://doc.rust-lang.org/core/hint/fn.unreachable_unchecked.html),
[`PartialEq`](https://doc.rust-lang.org/core/cmp/trait.PartialEq.html) and [`PartialOrd`](https://doc.rust-lang.org/core/cmp/trait.PartialOrd.html), which is what std uses, with
[`unreachable`](https://doc.rust-lang.org/core/macro.unreachable.html).
- `zeroize`: Allows deriving [`Zeroize`].
- `zeroize`: Allows deriving [`Zeroize`] and [`ZeroizeOnDrop`].

## MSRV

Expand Down Expand Up @@ -262,5 +275,6 @@ conditions.
[`Default`]: https://doc.rust-lang.org/core/default/trait.Default.html
[`Hash`]: https://doc.rust-lang.org/core/hash/trait.Hash.html
[`Zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html
[`ZeroizeOnDrop`]: https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html
[`method@zeroize`]: https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html#tymethod.zeroize
[#27]: https://github.com/ModProg/derive-where/issues/27
2 changes: 1 addition & 1 deletion ensure-no-std/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,4 @@ use derive_where::DeriveWhere;
#[derive(DeriveWhere)]
#[derive_where(Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd)]
#[cfg_attr(feature = "zeroize", derive_where(Zeroize))]
pub struct Test<T>(#[cfg_attr(feature = "zeroize", derive_where(skip(Zeroize)))] PhantomData<T>);
pub struct Test<T>(PhantomData<T>);
12 changes: 6 additions & 6 deletions non-msrv-tests/tests/ui/zeroize/item.stderr
Original file line number Diff line number Diff line change
@@ -1,34 +1,34 @@
error: unsupported trait, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:6:16
|
6 | #[derive_where(skip_inner, Clone)]
| ^^^^^^^^^^

error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:10:24
|
10 | #[derive_where(Debug = invalid; T)]
| ^^^^^^^

error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:14:16
|
14 | #[derive_where(,)]
| ^

error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:18:16
|
18 | #[derive_where(,Clone)]
| ^

error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait syntax, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:22:22
|
22 | #[derive_where(Clone,,)]
| ^

error: unsupported trait, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize
error: unsupported trait, expected one of expected one of Clone, Copy, Debug, Default, Eq, Hash, Ord, PartialEq, PartialOrd, Zeroize, ZeroizeOnDrop
--> tests/ui/zeroize/item.rs:26:16
|
26 | #[derive_where(T)]
Expand Down
20 changes: 0 additions & 20 deletions non-msrv-tests/tests/ui/zeroize/zeroize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,28 +24,8 @@ struct WrongCrateSyntax<T>(PhantomData<T>);
#[derive_where(Zeroize(crate = "struct Test"))]
struct InvalidCrate<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop, drop))]
struct DuplicateDrop<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(crate = "zeroize_", crate = "zeroize_"))]
struct DuplicateCrate<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop, drop, crate = "zeroize_"))]
struct DuplicateDropWithCrate<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop, crate = "zeroize_", crate = "zeroize_"))]
struct DropWithDuplicateCrate<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(crate = "zeroize_", crate = "zeroize_", drop))]
struct DuplicateCrateWithDrop<T>(PhantomData<T>);

#[derive(DeriveWhere)]
#[derive_where(Zeroize(crate = "zeroize_", drop, drop))]
struct CrateWithDuplicateDrop<T>(PhantomData<T>);

fn main() {}
34 changes: 2 additions & 32 deletions non-msrv-tests/tests/ui/zeroize/zeroize.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,8 @@ error: expected path, expected identifier
24 | #[derive_where(Zeroize(crate = "struct Test"))]
| ^^^^^^^^^^^^^

error: duplicate `drop` option
--> tests/ui/zeroize/zeroize.rs:28:30
|
28 | #[derive_where(Zeroize(drop, drop))]
| ^^^^

error: duplicate `crate` option
--> tests/ui/zeroize/zeroize.rs:32:44
--> tests/ui/zeroize/zeroize.rs:28:44
|
32 | #[derive_where(Zeroize(crate = "zeroize_", crate = "zeroize_"))]
28 | #[derive_where(Zeroize(crate = "zeroize_", crate = "zeroize_"))]
| ^^^^^^^^^^^^^^^^^^

error: duplicate `drop` option
--> tests/ui/zeroize/zeroize.rs:36:30
|
36 | #[derive_where(Zeroize(drop, drop, crate = "zeroize_"))]
| ^^^^

error: duplicate `crate` option
--> tests/ui/zeroize/zeroize.rs:40:50
|
40 | #[derive_where(Zeroize(drop, crate = "zeroize_", crate = "zeroize_"))]
| ^^^^^^^^^^^^^^^^^^

error: duplicate `crate` option
--> tests/ui/zeroize/zeroize.rs:44:44
|
44 | #[derive_where(Zeroize(crate = "zeroize_", crate = "zeroize_", drop))]
| ^^^^^^^^^^^^^^^^^^

error: duplicate `drop` option
--> tests/ui/zeroize/zeroize.rs:48:50
|
48 | #[derive_where(Zeroize(crate = "zeroize_", drop, drop))]
| ^^^^
5 changes: 4 additions & 1 deletion non-msrv-tests/tests/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
};

#[cfg(feature = "zeroize")]
use zeroize_::Zeroize;
use zeroize_::{Zeroize, ZeroizeOnDrop};

pub struct Wrapper<T = ()> {
data: i32,
Expand Down Expand Up @@ -44,6 +44,9 @@ impl<T> Zeroize for Wrapper<T> {
#[cfg(feature = "zeroize")]
pub struct AssertZeroize<'a, T: Zeroize>(pub &'a T);

#[cfg(feature = "zeroize")]
pub struct AssertZeroizeOnDrop<'a, T: ZeroizeOnDrop>(pub &'a T);

pub fn test_drop<T>(value: T, fun: impl FnOnce(&T)) {
let mut test_holder = vec![value];
let ptr = &mut test_holder[0] as *mut T;
Expand Down
11 changes: 7 additions & 4 deletions non-msrv-tests/tests/zeroize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use std::{
use derive_where::DeriveWhere;
use zeroize::Zeroize;

use self::util::{AssertZeroize, Wrapper};
use self::util::{AssertZeroize, AssertZeroizeOnDrop, Wrapper};

#[test]
fn basic() {
Expand Down Expand Up @@ -51,12 +51,13 @@ fn crate_() {
#[test]
fn drop() {
#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop))]
#[derive_where(Zeroize, ZeroizeOnDrop)]
struct Test<T>(Wrapper<T>);

let mut test = Test(42.into());

let _ = AssertZeroize(&test);
let _ = AssertZeroizeOnDrop(&test);

test.zeroize();

Expand All @@ -83,12 +84,13 @@ fn fqs() {
}

#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop))]
#[derive_where(Zeroize, ZeroizeOnDrop)]
struct Test<T>(#[derive_where(Zeroize(fqs))] Fqs<T>);

let mut test = Test(Fqs(42.into()));

let _ = AssertZeroize(&test);
let _ = AssertZeroizeOnDrop(&test);

test.zeroize();

Expand Down Expand Up @@ -116,12 +118,13 @@ fn deref() {
}

#[derive(DeriveWhere)]
#[derive_where(Zeroize(drop))]
#[derive_where(Zeroize, ZeroizeOnDrop)]
struct Test<T>(ZeroizeDeref<T>);

let mut test = Test::<()>(ZeroizeDeref(42, PhantomData));

let _ = AssertZeroize(&test);
let _ = AssertZeroizeOnDrop(&test);

test.zeroize();

Expand Down
20 changes: 18 additions & 2 deletions src/attr/item.rs
Original file line number Diff line number Diff line change
Expand Up @@ -309,8 +309,12 @@ pub enum DeriveTrait {
Zeroize {
/// [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) path.
crate_: Option<Path>,
/// [`Zeroize`](https://docs.rs/zeroize/latest/zeroize/trait.Zeroize.html) [`Drop`] implementation.
drop: bool,
},
/// [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html).
#[cfg(feature = "zeroize")]
ZeroizeOnDrop {
/// [`ZeroizeOnDrop`](https://docs.rs/zeroize/latest/zeroize/trait.ZeroizeOnDrop.html) path.
crate_: Option<Path>,
},
}

Expand Down Expand Up @@ -340,6 +344,8 @@ impl Deref for DeriveTrait {
PartialOrd => &Trait::PartialOrd,
#[cfg(feature = "zeroize")]
Zeroize { .. } => &Trait::Zeroize,
#[cfg(feature = "zeroize")]
ZeroizeOnDrop { .. } => &Trait::ZeroizeOnDrop,
}
}
}
Expand Down Expand Up @@ -421,6 +427,16 @@ impl DeriveTrait {
util::path_from_strs(&["zeroize", "Zeroize"])
}
}
#[cfg(feature = "zeroize")]
ZeroizeOnDrop { crate_, .. } => {
if let Some(crate_) = crate_ {
let mut crate_ = crate_.clone();
crate_.segments.push(util::path_segment("ZeroizeOnDrop"));
crate_
} else {
util::path_from_strs(&["zeroize", "ZeroizeOnDrop"])
}
}
}
}

Expand Down
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,8 @@ impl Error {
"PartialOrd",
#[cfg(feature = "zeroize")]
"Zeroize",
#[cfg(feature = "zeroize")]
"ZeroizeOnDrop",
]
.join(", ")
}
Expand Down
9 changes: 5 additions & 4 deletions src/input.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,10 +144,11 @@ impl<'a> Input<'a> {
#[cfg(feature = "zeroize")]
{
// `Zeroize(crate = "..")` is used.
if let DeriveTrait::Zeroize {
crate_: Some(_), ..
} = **trait_
{
if let DeriveTrait::Zeroize { crate_: Some(_) } = **trait_ {
continue;
}
// `ZeroizeOnDrop(crate = "..")` is used.
if let DeriveTrait::ZeroizeOnDrop { crate_: Some(_) } = **trait_ {
continue;
}
// `Zeroize(fqs)` is used on any field.
Expand Down
Loading