I found that mem::drop does not need to be run next to where it is called, which probably leads to the Mutex or RwLock being held during expensive computations. How can I control when calling drop ?
As a simple example, I performed the following test to drop cryptographic material trimming using unsafe { ::std::intrinsics::drop_in_place(&mut s); } unsafe { ::std::intrinsics::drop_in_place(&mut s); } instead of the simple ::std::mem::drop(s) .
#[derive(Debug, Default)] pub struct Secret<T>(pub T); impl<T> Drop for Secret<T> { fn drop(&mut self) { unsafe { ::std::intrinsics::volatile_set_memory::<Secret<T>>(self, 0, 1); } } } #[derive(Debug, Default)] pub struct AnotherSecret(pub [u8; 32]); impl Drop for AnotherSecret { fn drop(&mut self) { unsafe { ::std::ptr::write_volatile::<$t>(self, AnotherSecret([0u8; 32])); } assert_eq!(self.0,[0u8; 32]); } } #[cfg(test)] mod tests { macro_rules! zeroing_drop_test { ($n:path) => { let p : *const $n; { let mut s = $n([3u8; 32]); p = &s; unsafe { ::std::intrinsics::drop_in_place(&mut s); } } unsafe { assert_eq!((*p).0,[0u8; 32]); } } } #[test] fn zeroing_drops() { zeroing_drop_test!(super::Secret<[u8; 32]>); zeroing_drop_test!(super::AnotherSecret); } }
This test fails if I use ::std::mem::drop(s) or even
#[inline(never)] pub fn drop_now<T>(_x: T) { }
Obviously, use drop_in_place for the test so that the buffer is nullified, but I fear that calling drop_in_place in Mutex or RwLock may lead to use after free.
These two guards can be handled using this approach:
#[inline(never)] pub fn drop_now<T>(t: mut T) { unsafe { ::std::intrinsics::drop_in_place(&mut t); } unsafe { ::std::intrinsics::volatile_set_memory::<Secret<T>>(&t, 0, 1); } }
source share