On Tue, Nov 12, 2013 at 2:35 PM, Alex Crichton <[email protected]> wrote:
> 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. > It's undefined behaviour for a C++ function to throw an exception past an `extern "C"` boundary so Rust doesn't need to worry about a need to handle exceptions from foreign libraries. In practice, compilers will often build code with support for passing through exceptions but it's not required and C cannot maintain the invariants required for safety in the face of unwinding. It's simply not safe to pass Rust functions directly as callbacks into C if they aren't known to never throw. Rust isn't committed to using the C++ exception personality so interoperability with unwrapped C++ libraries just isn't on the table at this point. It actually *doesn't* even use the C++ exception personality because there are hooks to reset the used stack space.
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
