如何证明类型中毒?

时间:2017-11-04 04:25:28

标签: rust

我正在阅读The Rustonomicon,并遇到了section on poisoning。一个类型中毒的书面例子是当一个“ Mutex会在恐慌期间丢弃其中一个MutexGuards(它在获得锁定时返回的东西)时会自行中毒。”(Rustonomicon,第7.2节,第3段)

我很不自然,但突然很好奇。

为了找到类型中毒的实施演示,谷歌搜索“如何毒害一种类型”会产生无用的结果,从化学毒物类型列表到口袋妖怪。 “类型中毒的代码示例”的结果大致相同。

是否有人可以使用代码段演示类型中毒?我不在乎示例是否在Rust中,但也许这很重要......因为在某些语言中只能以某种方式中毒?

我发现中毒发生在其他语言中,或至少C++ function poisoningnamespace poisoning。 (搜索“Java类型中毒”会因检测java bean poisoned dogshow to poison mobs in Minecraft而产生无用但有趣的结果。)

然而,这些示例缺少代码中的示例链接。我希望看到它在行动。

1 个答案:

答案 0 :(得分:4)

通过检查Drop实施中std::thread::panicking的返回值来实现中毒。如果它返回true,则该值应该中毒。这是一个例子:

use std::cell::Cell;
use std::panic::{self, AssertUnwindSafe};
use std::thread;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum ResourceState {
    Available,
    Locked,
    Poisoned,
}

struct Resource {
    state: Cell<ResourceState>,
}

struct ResourceGuard<'a> {
    resource: &'a Resource,
}

impl Resource {
    fn new() -> Resource {
        Resource {
            state: Cell::new(ResourceState::Available),
        }
    }

    fn lock(&self) -> ResourceGuard {
        assert_eq!(self.state.get(), ResourceState::Available);
        self.state.set(ResourceState::Locked);
        ResourceGuard {
            resource: self,
        }
    }
}

impl<'a> Drop for ResourceGuard<'a> {
    fn drop(&mut self) {
        self.resource.state.set(
            if thread::panicking() {
                ResourceState::Poisoned
            } else {
                ResourceState::Available
            });
    }
}

fn main() {
    let resource = Resource::new();
    println!("state: {:?}", resource.state.get()); // Available

    {
        println!("acquiring lock");
        let _guard = resource.lock();
        println!("state: {:?}", resource.state.get()); // Locked
        println!("dropping lock");
    }

    println!("state: {:?}", resource.state.get()); // Available

    let _ = panic::catch_unwind(AssertUnwindSafe(|| {
        println!("acquiring lock");
        let _guard = resource.lock();
        println!("state: {:?}", resource.state.get()); // Locked
        println!("panicking!");
        panic!("panicking!");
    }));

    println!("state: {:?}", resource.state.get()); // Poisoned
}