Skip to content

Commit 9af5365

Browse files
Merge pull request #238 from iqlusioninc/zeroize/fix-nightly-support
zeroize: Improved attribute parser (fixes #237)
2 parents 1c16876 + d94174a commit 9af5365

File tree

3 files changed

+51
-22
lines changed

3 files changed

+51
-22
lines changed

zeroize/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ This crate provides a safe<sup>†</sup>, portable access to cross-platform
1313
intrinsics for securely zeroing memory which are specifically documented as
1414
guaranteeing they won't be "optimized away".
1515

16-
The [`Zeroize` trait] is the crate's primary (and only) API.
16+
The [`Zeroize` trait] is the crate's primary API.
1717

1818
[Documentation]
1919

zeroize/src/lib.rs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,13 @@
5252
//!
5353
//! ## Custom Derive Support
5454
//!
55-
//! **NOTICE**: Previous versions of `zeroize` automatically derived
56-
//! `Drop`. This has been *REMOVED* and you now *MUST* explicitly specify
57-
//! either `zeroize(drop)` or `zeroize(no_drop)` (see below).
58-
//!
5955
//! This crate has custom derive support for the `Zeroize` trait, which
6056
//! automatically calls `zeroize()` on all members of a struct or tuple struct.
6157
//!
62-
//! Additionally it supports the following attributes (you *MUST* pick one):
58+
//! Additionally it supports the following attributes:
6359
//!
64-
//! - `#[zeroize(no_drop)]`: derive only `Zeroize` without adding a `Drop` impl
6560
//! - `#[zeroize(drop)]`: call `zeroize()` when this item is dropped
61+
//! - `#[zeroize(no_drop)]`: legacy attribute which will be removed in `zeroize` 1.0
6662
//!
6763
//! Example which derives `Drop`:
6864
//!
@@ -82,7 +78,6 @@
8278
//!
8379
//! // This struct will *NOT* be zeroized on drop
8480
//! #[derive(Copy, Clone, Zeroize)]
85-
//! #[zeroize(no_drop)]
8681
//! struct MyStruct([u8; 32]);
8782
//! ```
8883
//!

zeroize_derive/src/lib.rs

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,55 +8,89 @@ extern crate proc_macro;
88

99
use proc_macro2::TokenStream;
1010
use quote::quote;
11+
use syn::{Attribute, Ident, Meta, NestedMeta};
1112
use synstructure::{decl_derive, BindStyle};
1213

1314
/// Name of zeroize-related attributes
1415
const ZEROIZE_ATTR: &str = "zeroize";
1516

1617
/// Custom derive for `Zeroize`
1718
fn derive_zeroize(s: synstructure::Structure) -> TokenStream {
18-
let attributes = ZeroizeDeriveAttrs::parse(&s);
19+
let attributes = DeriveAttrs::parse(&s);
1920

2021
match attributes.drop {
2122
Some(true) => derive_zeroize_with_drop(s),
22-
Some(false) => derive_zeroize_without_drop(s),
23-
None => panic!("must specify either zeroize(drop) or zeroize(no_drop) attribute"),
23+
Some(false) | None => derive_zeroize_without_drop(s),
2424
}
2525
}
2626
decl_derive!([Zeroize, attributes(zeroize)] => derive_zeroize);
2727

2828
/// Custom derive attributes for `Zeroize`
29-
struct ZeroizeDeriveAttrs {
29+
struct DeriveAttrs {
3030
/// Derive a `Drop` impl which calls zeroize on this type
3131
drop: Option<bool>,
3232
}
3333

34-
impl Default for ZeroizeDeriveAttrs {
34+
impl Default for DeriveAttrs {
3535
fn default() -> Self {
3636
Self { drop: None }
3737
}
3838
}
3939

40-
impl ZeroizeDeriveAttrs {
40+
impl DeriveAttrs {
4141
/// Parse attributes from the incoming AST
4242
fn parse(s: &synstructure::Structure) -> Self {
4343
let mut result = Self::default();
4444

4545
for v in s.variants().iter() {
4646
for attr in v.ast().attrs.iter() {
47-
if attr.path.is_ident(ZEROIZE_ATTR) {
48-
// TODO(tarcieri): hax, but probably good enough for now
49-
match attr.tts.to_string().as_ref() {
50-
"( drop )" => result.drop = Some(true),
51-
"( no_drop )" => result.drop = Some(false),
52-
other => panic!("unknown zeroize attribute: {}", other),
53-
}
54-
}
47+
result.parse_attr(attr);
5548
}
5649
}
5750

5851
result
5952
}
53+
54+
/// Parse attribute and handle `#[zeroize(...)]` attributes
55+
fn parse_attr(&mut self, attr: &Attribute) {
56+
let meta = attr
57+
.parse_meta()
58+
.unwrap_or_else(|e| panic!("error parsing attribute: {} ({})", attr.tts, e));
59+
60+
if let Meta::List(list) = meta {
61+
if list.ident != ZEROIZE_ATTR {
62+
return;
63+
}
64+
65+
for nested_meta in &list.nested {
66+
if let NestedMeta::Meta(Meta::Word(ident)) = nested_meta {
67+
self.parse_attr_ident(ident);
68+
} else {
69+
panic!("malformed #[zeroize] attribute: {:?}", nested_meta);
70+
}
71+
}
72+
}
73+
}
74+
75+
/// Parse a `#[zeroize(...)]` attribute containing a single ident (e.g. `drop`)
76+
fn parse_attr_ident(&mut self, ident: &Ident) {
77+
if ident == "drop" {
78+
self.set_drop_flag(true);
79+
} else if ident == "no_drop" {
80+
self.set_drop_flag(false);
81+
} else {
82+
panic!("unknown #[zeroize] attribute type: {}", ident);
83+
}
84+
}
85+
86+
/// Set the value of the `drop` flag
87+
fn set_drop_flag(&mut self, value: bool) {
88+
if self.drop.is_some() {
89+
panic!("duplicate #[zeroize] drop/no_drop flags");
90+
} else {
91+
self.drop = Some(value);
92+
}
93+
}
6094
}
6195

6296
/// Custom derive for `Zeroize` (without `Drop`)

0 commit comments

Comments
 (0)