diff --git a/zeroize/README.md b/zeroize/README.md
index 9e798a4a..5349b61a 100644
--- a/zeroize/README.md
+++ b/zeroize/README.md
@@ -13,7 +13,7 @@ This crate provides a safe†, portable access to cross-platform
intrinsics for securely zeroing memory which are specifically documented as
guaranteeing they won't be "optimized away".
-The [`Zeroize` trait] is the crate's primary (and only) API.
+The [`Zeroize` trait] is the crate's primary API.
[Documentation]
diff --git a/zeroize/src/lib.rs b/zeroize/src/lib.rs
index e2f57f15..379bbc92 100644
--- a/zeroize/src/lib.rs
+++ b/zeroize/src/lib.rs
@@ -52,17 +52,13 @@
//!
//! ## Custom Derive Support
//!
-//! **NOTICE**: Previous versions of `zeroize` automatically derived
-//! `Drop`. This has been *REMOVED* and you now *MUST* explicitly specify
-//! either `zeroize(drop)` or `zeroize(no_drop)` (see below).
-//!
//! This crate has custom derive support for the `Zeroize` trait, which
//! automatically calls `zeroize()` on all members of a struct or tuple struct.
//!
-//! Additionally it supports the following attributes (you *MUST* pick one):
+//! Additionally it supports the following attributes:
//!
-//! - `#[zeroize(no_drop)]`: derive only `Zeroize` without adding a `Drop` impl
//! - `#[zeroize(drop)]`: call `zeroize()` when this item is dropped
+//! - `#[zeroize(no_drop)]`: legacy attribute which will be removed in `zeroize` 1.0
//!
//! Example which derives `Drop`:
//!
@@ -82,7 +78,6 @@
//!
//! // This struct will *NOT* be zeroized on drop
//! #[derive(Copy, Clone, Zeroize)]
-//! #[zeroize(no_drop)]
//! struct MyStruct([u8; 32]);
//! ```
//!
diff --git a/zeroize_derive/src/lib.rs b/zeroize_derive/src/lib.rs
index 1c01f6e3..3a64b69b 100644
--- a/zeroize_derive/src/lib.rs
+++ b/zeroize_derive/src/lib.rs
@@ -8,6 +8,7 @@ extern crate proc_macro;
use proc_macro2::TokenStream;
use quote::quote;
+use syn::{Attribute, Ident, Meta, NestedMeta};
use synstructure::{decl_derive, BindStyle};
/// Name of zeroize-related attributes
@@ -15,48 +16,81 @@ const ZEROIZE_ATTR: &str = "zeroize";
/// Custom derive for `Zeroize`
fn derive_zeroize(s: synstructure::Structure) -> TokenStream {
- let attributes = ZeroizeDeriveAttrs::parse(&s);
+ let attributes = DeriveAttrs::parse(&s);
match attributes.drop {
Some(true) => derive_zeroize_with_drop(s),
- Some(false) => derive_zeroize_without_drop(s),
- None => panic!("must specify either zeroize(drop) or zeroize(no_drop) attribute"),
+ Some(false) | None => derive_zeroize_without_drop(s),
}
}
decl_derive!([Zeroize, attributes(zeroize)] => derive_zeroize);
/// Custom derive attributes for `Zeroize`
-struct ZeroizeDeriveAttrs {
+struct DeriveAttrs {
/// Derive a `Drop` impl which calls zeroize on this type
drop: Option,
}
-impl Default for ZeroizeDeriveAttrs {
+impl Default for DeriveAttrs {
fn default() -> Self {
Self { drop: None }
}
}
-impl ZeroizeDeriveAttrs {
+impl DeriveAttrs {
/// Parse attributes from the incoming AST
fn parse(s: &synstructure::Structure) -> Self {
let mut result = Self::default();
for v in s.variants().iter() {
for attr in v.ast().attrs.iter() {
- if attr.path.is_ident(ZEROIZE_ATTR) {
- // TODO(tarcieri): hax, but probably good enough for now
- match attr.tts.to_string().as_ref() {
- "( drop )" => result.drop = Some(true),
- "( no_drop )" => result.drop = Some(false),
- other => panic!("unknown zeroize attribute: {}", other),
- }
- }
+ result.parse_attr(attr);
}
}
result
}
+
+ /// Parse attribute and handle `#[zeroize(...)]` attributes
+ fn parse_attr(&mut self, attr: &Attribute) {
+ let meta = attr
+ .parse_meta()
+ .unwrap_or_else(|e| panic!("error parsing attribute: {} ({})", attr.tts, e));
+
+ if let Meta::List(list) = meta {
+ if list.ident != ZEROIZE_ATTR {
+ return;
+ }
+
+ for nested_meta in &list.nested {
+ if let NestedMeta::Meta(Meta::Word(ident)) = nested_meta {
+ self.parse_attr_ident(ident);
+ } else {
+ panic!("malformed #[zeroize] attribute: {:?}", nested_meta);
+ }
+ }
+ }
+ }
+
+ /// Parse a `#[zeroize(...)]` attribute containing a single ident (e.g. `drop`)
+ fn parse_attr_ident(&mut self, ident: &Ident) {
+ if ident == "drop" {
+ self.set_drop_flag(true);
+ } else if ident == "no_drop" {
+ self.set_drop_flag(false);
+ } else {
+ panic!("unknown #[zeroize] attribute type: {}", ident);
+ }
+ }
+
+ /// Set the value of the `drop` flag
+ fn set_drop_flag(&mut self, value: bool) {
+ if self.drop.is_some() {
+ panic!("duplicate #[zeroize] drop/no_drop flags");
+ } else {
+ self.drop = Some(value);
+ }
+ }
}
/// Custom derive for `Zeroize` (without `Drop`)