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

Reply via email to