-1

I was reading The Rustonomicon, and came across its section on poisoning. One written example of type poisoning is when a "Mutex will poison itself if one of its MutexGuards (the thing it returns when a lock is obtained) is dropped during a panic." (Rustonomicon, section 7.2, paragraph 3)

I'm pretty out of my depth, but suddenly very curious.

In an effort to find an implemented demonstration of type poisoning, Googling "how to poison a type" yields useless results ranging from lists of chemical poison types, to Pokemon. "Code example of type poisoning" is much the same result.

Is there someone who can demonstrate type poisoning with a code snippet? I don't care if the example is in Rust or not, but maybe that's important... as in some languages can only be poisoned in certain ways maybe?

I see that poisoning happens in other languages, or at least C++ function poisoning, and namespace poisoning. (searching for "Java type poisoning" yields useless but interesting results from detecting java bean poisoned dogs, to how to poison mobs in Minecraft.)

And yet those examples lack links to examples in code. I was hoping to see it in action.

NonCreature0714
  • 5,744
  • 10
  • 30
  • 52
  • Well... Live and learn... I just Googled "rust type poisoning" and found this: https://doc.rust-lang.org/std/sync/struct.Mutex.html – NonCreature0714 Nov 04 '17 at 04:34
  • The question does not make it clear what you mean by "demonstrate type poisoning with code". Are you looking for a demonstration of the *concept* of poisoning (what it means to poison an object and why someone would want to do that), a particular *implementation* of poisoning (e.g. the one in Rust mutexes), or an example of *using* a poisonable type? Francois's answer shows a minimal complete implementation of the concept in Rust. – user4815162342 Nov 04 '17 at 13:17
  • That’s true, his answer does show a MVCE implementation, but I wanted to wait an appropriate amount of time before accepting. While it would be very useful to have someone demonstrate the concept of poisoning and why it may be done intentionally, it’s not what I was asking for, so I’ll clarify. – NonCreature0714 Nov 04 '17 at 16:47
  • 1
    You might be reading too much magic into the whole "poisoning" thing. It's just an exotic name for a a fairly ordinary concept, which is an object supporting an explicit "corrupted" flag. An object so flagged tries to fail as early as possible instead of allowing you to proceed and failing later in ways that are subtler and harder to debug. In a language with exceptions, that object would throw an exception whenever you access it. In Rust its public methods return error `Result`s. – user4815162342 Nov 04 '17 at 16:59
  • @user4815162342 I’m not sure where implied I thought type poisoning was “magic.” I was simply curious because it’s a new concept, and encountering newness doesn’t mean naïveté. I’m also not sure why my question was downvoted, and I’m not implying you did, because I clearly showed research, it is related to programming or software development, it isn’t overlong, and I’m specific looking for a [mcve] to help explain a subject which has few q’s of its kind on SO. It lead to a good, informational answer on a subject which the Rust-Lang creators strongly infer is obscure. Way to kill curiosity SO. – NonCreature0714 Nov 05 '17 at 20:37
  • My objection to the question is explained in my first comment, it's simply unclear what you're asking about, i.e. what's unclear to you in the nomicon explanation you linked. The whole point is now moot, though, with the question being answered and the answer accepted. And as for the downvote, don't let it get to you - downvotes happen on StackOverflow, and an individual downvote is never a big deal. – user4815162342 Nov 05 '17 at 20:51
  • @user4815162342 thanks, it is definitely moot now. I was more frustrated by the downvote, especially since I put in a good amount of time on the question. – NonCreature0714 Nov 05 '17 at 22:31

1 Answers1

4

Poisoning is implemented by checking the return value of std::thread::panicking within a Drop implementation. If it returns true, then the value should be poisoned. Here's an example:

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
}
Francis Gagné
  • 60,274
  • 7
  • 180
  • 155