In this reddit post I asked what might cause corruption if std::rt::unwind::try is being nested. At the end of the discussion I was advised to post my question here.
So can corruption occur in the recent versions rustc if std::rt::unwind::try is being nested? If it can, under what circumstances it happens and can it be fixed without much hassle? If it cannot, shouldn’t someone update the docs?
We also discussed the unsafety of the function. Reddit user riccieri explained that even if no corruption occurs, the panic in the closure can leave some objects in inconsistent state. A similar argument was being made for Thread::scoped and that’s why it propagates panics in the recent versions.
But if the closure passed to std::rt::unwind::try is 'static (most of) the inconsistent objects cannot be reached. Reddit user wrongerontheinternet even proposed adding a poison bit to RefCell, so if there are no unsafe sections no object affected by the panicking environment is reachable after the return of std::rt::unwind::try.
So to refine my second question:
Assuming it is safe to nest std::rt::unwind::try, can we make a safe function with similar semantics with the above-mentioned suggestions?
So I actually do think there is one problem with this: thread locals (equivalent to statics in the multithreaded scenario). We bound static variables by Sync, which lets us control what we put there with that trait, but thread locals have no such bound. Thus, if a poison bit is too expensive for RefCell in the normal, no-try case (and it probably is–it isn’t dwarfed by the cost of the lock like Mutex), there isn’t any real way of preventing exception safety issues in thread locals. Unfortunately I think the right way to do this (create parallel traits for single threaded exception safety, bound thread locals by them, and create an alternate RefCell [and likely Cell]) would have to have already happened by now, as doing this would break lots of existing code (unless the thread local stuff is not going to be stable for 1.0?).
I think that’s the only major problem. With OIBIT and without thread locals, we could easily prevent direct sharing of thread memory altogether by using Send + 'static (and we’ve already implicitly agreed that anything else that makes it through that bound is okay to mutate, which I would like better frankly since Cell and RefCell aren’t exactly like atomics and mutexes; in particular, you don’t usually assume that someone else might access them the moment after you release the “lock”).
I’ve read a little about thread local variables in Rust. If I understand correctly they can be (safely) muted only in the closure passed to the with method. If the closure finishes without panicking the variable should be in consistent state. So accessing it after panicking shouldn’t be a problem. But if the closure panics the variable might be in inconsistent state. If the thread local is poisoned only if the closure passed to the with method panics (which can be done quite cheaply), shouldn’t everything be okay?
From your answer I understand that apart from variables being left in inconsistent state(but all the drop methods are called correctly), the std::rt::unwind::try is safe to nest?