Is jumping over Rust stack frames UB in a context of FFI?

I have a following use-case: C program links to Rust library. During execution the following thing may happen:

  • C uses setjmp as a restoration point
  • C calls Rust
    • Rust calls back to C
  • C encounters an error and makes a longjmp back to the point previously saved in C

I do understand that by doing this non of Rust's memory is freed (and non of the Drop impls are called). While I can partially work around the memory issue I am wondering if I should consider skipping over Rust stack frames being an undefined behavior? Or is it limited only to memory allocation and Drop not being called in such case?

3 Likes

See:

tl;dr: It has been tried to make unwinding past rust code abort. However setjmp/longjmp uses unwinding on Windows, which meant that a project using setjmp/longjmp broke on Windows. There is currently a discussion about how to support unwinding between rust and C without preventing some optimizations and without having to commit to a certian panic implementation. (We may want to use something other than DWARF/SEH unwinding in the future)

Conclusion: you should avoid it at least for the time being.

3 Likes

The original bug on Windows has been fixed! @alexcrichton has stated that "you can always longjmp across rust frames".

If you're interested in using unwinding with destructors across FFI boundaries, you can do so on nightly using an unstable annotation, #[unwind(allowed)] . There is indeed a team working on providing a stable way to do this, though; if you'd like to help out, provide input/feedback/use-cases, or just monitor progress, our repo is where to start.

2 Likes

Thanks @bjorn3 for all the links. Give me a lot of insights into the whole topic but still a lot to process.

@BatmanAoD this is what I was looking for. I think I have got a clearer mental picture of what can/canno happen if the C code I am trying to call will longjmp. The library I am trying to interoperate with is PHP's internals. Last but probably not least, this jump happens during memory allocation so it is called from within GlobalAllocator. Still need to prove if/what kind of consequences this will have.

1 Like