有没有什么安全的方法可以确保在一些昂贵的计算之前发生任意丢弃?

Jef*_*ges 5 multithreading raii rust

我发现mem::drop没有必要在它被调用的地方附近运行,这可能导致在昂贵的计算过程中保持MutexRwLock守卫.如何控制何时drop被调用?

作为一个简单的例子,我通过使用unsafe { ::std::intrinsics::drop_in_place(&mut s); }而不是简单地对密码材料工作的归零进行了以下测试::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);
    }
}
Run Code Online (Sandbox Code Playgroud)

如果我使用::std::mem::drop(s)或甚至使用此测试失败

#[inline(never)]
pub fn drop_now<T>(_x: T) { }
Run Code Online (Sandbox Code Playgroud)

显然很好drop_in_place用于缓冲区变为零的测试,但是我担心调用drop_in_place一个Mutex或一个RwLock后卫可能会导致免费使用.

可以用这种方法处理这两个警卫:

#[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); }
}
Run Code Online (Sandbox Code Playgroud)

Mat*_* M. 3

是的:副作用。

一般来说,优化器,特别是 LLVM,在 as-if 规则下运行:您构建一个具有特定可观察行为的程序,并且优化器可以自由地生成它想要的任何二进制文件,只要它具有完全相同的可观察行为行为。

请注意,举证责任在于编译器。也就是说,当调用不透明函数(例如在另一个库中定义)时,编译器必须假设它可能有副作用。此外,副作用不能重新排序,因为这可能会改变可观察的行为。

例如,在 的情况下Mutex,获取和释放Mutex通常对于编译器来说是不透明的(它需要操作系统调用),因此它被视为副作用。我希望编译器不要摆弄这些。

另一方面,你的Secret情况很棘手:大多数时候,删除秘密并没有副作用(将要释放的内存清零是死写,需要优化),这就是为什么你需要不遗余力地确保它发生......通过让编译器相信使用写入会产生副作用volatile