Zauważyłem, że mem::drop
nie trzeba uruchamiać w pobliżu miejsca, w którym zostanie wywołany, co prawdopodobnie skutkuje przetrzymaniem strażników podczas kosztownych obliczeń. Jak mogę kontrolować, kiedy zostanie wywołana drop
?Czy istnieje jakiś bezpieczny sposób na zapewnienie, że nastąpi dowolny zrzut przed kosztownym obliczeniem?
Jako prosty przykład, wykonałem następujący test zerującego spadku materiału kryptograficznego przy użyciu unsafe { ::std::intrinsics::drop_in_place(&mut s); }
zamiast po prostu ::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);
}
}
Ten test nie powiedzie się, jeśli mogę użyć ::std::mem::drop(s)
lub nawet
#[inline(never)]
pub fn drop_now<T>(_x: T) { }
jest to oczywiście dobrze używać drop_in_place
na test, że bufor zostanie wyzerowany, ale będę się martwić, że nazywając drop_in_place
na Mutex
lub RwLock
ochrona może spowodować użycie po bezpłatnym.
Te dwie osłony mogłyby być może być traktowane z takim podejściem:
#[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); }
}
Podniosłem to jako problem z kompilatorem rdzy https://github.com/rust-lang/rfcs/issues/1850 po stwierdzeniu, że procesowanie potoku CPU itp. Nie było sprawcami. –
Odpowiedź: nie należy umieszczać tajnego materiału klucza na stosie, ponieważ wszystko na stosie zostanie skopiowane. –
może dodać [ogrodzenie] (https://doc.rust-lang.org/std/sync/atomic/fn.fence.html). AIUI, które powinno zapobiegać zmianie kolejności. – the8472