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

Reply via email to