J'ai trouvé que mem::drop
ne fonctionne pas nécessaire près de là où il est appelé, dont les résultats probables dans Mutex
ou RwLock
gardes détenus pendant des calculs coûteux. Comment puis-je contrôler quand drop
est appelé?Existe-t-il un moyen sûr d'assurer une chute arbitraire avant un calcul coûteux?
Comme un exemple simple, j'ai fait le test suivant pour une réduction à zéro du matériel cryptographique en utilisant unsafe { ::std::intrinsics::drop_in_place(&mut s); }
au lieu de simplement ::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);
}
}
Ce test échoue si j'utilise ::std::mem::drop(s)
ou même
#[inline(never)]
pub fn drop_now<T>(_x: T) { }
Il est évidemment bon d'utiliser drop_in_place
pour un test qu'un tampon se remis à zéro, mais je me inquiéterais que l'appel drop_in_place
sur un Mutex
ou RwLock
garde pourrait entraîner une utilisation après libre.
Ces deux gardiens pourraient peut-être être manipulés avec cette approche:
#[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); }
}
J'ai soulevé cela comme un problème avec le compilateur de rouille https://github.com/rust-lang/rfcs/issues/1850 après avoir identifié que la mise en pipeline de processeurs, etc., n'étaient pas les coupables. –
La réponse est de ne jamais mettre de matériel de clé secrète sur la pile car tout ce qui se trouve sur la pile est copié. –
peut-être ajouter un [clôture] (https://doc.rust-lang.org/std/sync/atomic/fn.fence.html). AIUI qui devrait empêcher le réordonnancement. – the8472