You're correct about the safeness of catching failure at a task boundary. Rust's invariants about spawning a task involve knowing a fair bit about what's allowable to share between a task boundary, and that allows us to reason about the failure unwinding to the task boundary being a safe operation (as opposed to stopping unwinding at an arbitrary location).
I'm not entirely sure what you mean by throwing an exception from C (I think there are many flavors of doing this). Right now we implement unwinding via C++ exceptions. When a task unwinds, it actually throws a magical uint token which then triggers all the C++ machinery for unwinding the stack. When compiling with LLVM, we using LLVM's invoke instruction + landing pads to generate our "cleanup locations", and LLVM will codegen the right code such that all the landing pads are invoked during unwinding. What this means is that the C++ exception throwing infrastructure will probably fly right past all C code because none of it is hooked into the exception handling stuff of C++. This may mean, however, that intermediate C++ code may have landing pads run (not entirely sure). All that being said, that's just how it's currently implemented today. I don't think that we're guaranteeing this sort of behavior to always happen. It will probably always be the case that C stack frames are always sailed past during unwinding, but we may implement unwinding via precise stack tables and manual stack unwinding at some point which wouldn't trigger C++ landing pads (or use LLVM's landing pad infrastructure the same way that we're using it today). Right now it's basically the case that intermingling C with Rust stack frames and then triggering failure will only trigger unwinding in rust functions (what does it mean to unwind in C?), and I'm not sure I'd recommend that as a safe strategy for implementing bindings to a C function (all intermediate C allocations are leaked). Does that make sense? It may not quite answer your question, but hopefully that clears up at least a little bit about how it's implemented today. On Tue, Nov 12, 2013 at 11:07 AM, Kevin Ballard <ke...@sb.org> wrote: > Right now, Rust does not support catching task failure from within a task, it > only supports preventing task failure from cascading into other tasks. My > understanding is that this limitation is done because of safety; if a task > unwinds through a few frames of code, and then stops unwinding, data > structure invariants may have been broken by the unwinding, leaving the task > in an unsafe state. Is this correct? > > Given this assumption, my worry now is about task unwinding outside of the > control of Rust. Namely, if I’m using Rust to write a library with extern “C” > functions, or I’m providing callbacks to C code from within Rust, (and my > Rust code calls back into C at some point), then it’s very possible for the > called C code to throw an exception that is then caught in the calling C code > a few frames up. The net effect is that the thread will unwind through my > Rust code, but it will then be caught before unwinding any further, > potentially leaving any data structures in an invalid state (assuming that > there’s still Rust code higher up on this same stack that cares). > > Has this been considered before? Is this actually a danger or am I just being > paranoid? > > -Kevin > _______________________________________________ > Rust-dev mailing list > Rust-dev@mozilla.org > https://mail.mozilla.org/listinfo/rust-dev _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev