-
Notifications
You must be signed in to change notification settings - Fork 150
Description
The Zeroizing struct is currently declared with a generic bound of <Z: Zeroize>, which means that Z is implicitly required to be Sized. This means that it's not currently possible to define types like Box<Zeroizing<[T]>> or Arc<Zeroizing<[T]>>, which would be useful in many contexts. In particular, both of these constructions are safer than using Zeroizing<Vec<T>> because they don't support potentially re-allocating resize operations, which can circumvent the desired guarantees of Zeroizing.
It's possible to emulate the functionality of Box<Zeroizing<[T]>> by defining struct like:
struct ZeroizingBox<T: Zeroize + ?Sized>(Box<T>);
impl<T: Zeroize + ?Sized> ZeroizingBox<T> {
pub fn new(b: Box<T>) -> Self {
Self(b)
}
}
impl<T: Zeroize + ?Sized> Drop for ZeroizingBox<T> {
fn drop(&mut self) {
self.0.zeroize();
}
}but this is a bit cumbersome. I don't think there's a good way to emulate Arc<Zeroizing<[T]>> because there's no way from outside the Arc to mutably access the slice contents in a drop impl. The best you could do is probably Arc<ZeroizingBox<[T]>> using the construction above.
The fix for this would be to update the definition of Zeroizing to:
pub struct Zeroizing<Z: Zeroize + ?Sized>(Z);Initially I thought that this would be a breaking change, because someone might have written code like:
fn use_by_value<T>(z: Zeroizing<T>) {
// ...
}However, in a case like this the T is implicitly Sized, so there's actually no breakage here. More generally, any code that exists today and forms a Zeroizing<T> must already have an implied or explicit T: Sized bound, so any such code that works today should continue to work without that bound.
It's possible there could be more complex scenarios with breakage breakage involving overlapping blanket trait implementations, but I haven't been able to think of a straightforward one.