Stream: wg-ffi-unwind

Topic: gnzlbg minimal requirements


gnzlbg (Oct 15 2019 at 19:25, on Zulip):

Yes. That s just my current brain dump

gnzlbg (Oct 15 2019 at 19:26, on Zulip):

I was working with some thread cancellation issues in the UCGs and ended up needing this feature

gnzlbg (Oct 15 2019 at 19:26, on Zulip):

So I started down explaining my problem and what guarantees I need

nikomatsakis (Oct 15 2019 at 19:26, on Zulip):

seems useful, yes

gnzlbg (Oct 15 2019 at 19:26, on Zulip):

Those are implementable on Linux at least

gnzlbg (Oct 15 2019 at 19:26, on Zulip):

There are some references to the relevant specs

nikomatsakis (Oct 15 2019 at 19:27, on Zulip):

I spun this out into its own topic

gnzlbg (Oct 15 2019 at 19:30, on Zulip):

So for background: https://rust-lang.zulipchat.com/#narrow/stream/136281-t-lang.2Fwg-unsafe-code-guidelines/topic/pthread_cancel.20looks.20unsound and https://github.com/rust-lang/rust-memory-model/issues/46

gnzlbg (Oct 15 2019 at 19:30, on Zulip):

Basically, on Linux (or POSIX) in general, pthreads has cancellation points on a lost of C library APIs, like open, sleep, and so on

gnzlbg (Oct 15 2019 at 19:31, on Zulip):

when a thread is cancelled, those functions unwind

gnzlbg (Oct 15 2019 at 19:32, on Zulip):

In the Itanium C++ ABI, there are ~3 types of unwinds, "native" (whatever the current programming language uses), "foreign" (what other programming languages that are not the current one uses), and "forced" (the stack frames do not control unwinding, but something external does, so the current stack frames cannot just stop unwinding completely, they can pause it, but must resume it - think longjmp where the stack frames being deallocated cannot stop it, only setjmp can, or thread cancellation..)

gnzlbg (Oct 15 2019 at 19:34, on Zulip):

I think this might be simpler in the C ABI (the x86-ps-abi), but a lot of the wording there about unwinding is identical to the itanium ABI spec (the itanium builds on that one, so they aren't really incompatible)

gnzlbg (Oct 15 2019 at 19:35, on Zulip):

So that's it, when you spawn a thread, and call pthread_cancel on its thread id, some extern "C" function in libc unwinds, and that's UB - I need to make those "C unwind" instead

gnzlbg (Oct 15 2019 at 19:36, on Zulip):

since we want to spawn new threads that start a Rust function, this is Rust (spawns thread)->C (pthread_create)->Rust (the callback that gets started)->C (a call to open or something that can cancel the thread)

gnzlbg (Oct 15 2019 at 19:36, on Zulip):

So I need Rust->C to work, where C unwinds with a non-Rust unwinding, over Rust frames

gnzlbg (Oct 15 2019 at 19:36, on Zulip):

Rust threads on Linux contain all kind of stuff, so the T: Copy restriction for stackframes isn't enough

gnzlbg (Oct 15 2019 at 19:37, on Zulip):

pthreads cancels threads with "forced unwinding", so catch_unwind needs to be implemented to ignore those on linux

gnzlbg (Oct 15 2019 at 19:38, on Zulip):

I have no idea what happens when -C panic=abort and "force unwinding"

gnzlbg (Oct 15 2019 at 19:38, on Zulip):

probably the frames are just deallocated like a longjmp, so that would be unsound over non T: Copy frames

Adam C. Foltzer (Oct 16 2019 at 20:08, on Zulip):

yikes, I didn't realize that pthread_cancel does that, though it makes sense

Adam C. Foltzer (Oct 16 2019 at 20:09, on Zulip):

I have no idea what happens when -C panic=abort and "force unwinding"

I know we don't emit landing pads with panic=abort, but is the .eh_frame still emitted I wonder? if not, I'm guessing the system unwinder would fail and abort the process

gnzlbg (Oct 17 2019 at 08:52, on Zulip):

So IIUC what happens with -C panic=abort is that we still unwind, but I don't know if destructors are run or not run consistently yet

gnzlbg (Oct 17 2019 at 08:53, on Zulip):

We probably could guard FFI calls to "C unwind" functions with code that causes an abort when -C panic=abort

gnzlbg (Oct 17 2019 at 08:54, on Zulip):

But I think the real issue here is that when we say that it is UB for extern "C" to unwind, that requirement might be too strong

gnzlbg (Oct 17 2019 at 08:54, on Zulip):

since it would prevent longjmp on platforms where it is implemented by a particular kind of unwind, that LLVM supports even for nounwind functions

gnzlbg (Oct 17 2019 at 08:54, on Zulip):

and it would also prevent thread cancellation, which uses this exact same mechanism

gnzlbg (Oct 17 2019 at 08:55, on Zulip):

I think I would be fine with making this requirement for extern "C" functions

gnzlbg (Oct 17 2019 at 08:55, on Zulip):

that would require those functions to use "C unwind" instead

gnzlbg (Oct 17 2019 at 08:56, on Zulip):

as long as we allow "C unwind" functions to still unwind in some cases even when -C panic=abort

gnzlbg (Oct 17 2019 at 08:57, on Zulip):

e.g. by allowing these to unwind with certain platform specific mechanisms as long as doing so does not break any safety invariants that rely on destructors being run, like Pin, or crossbeam::scope

gnzlbg (Oct 17 2019 at 08:57, on Zulip):

for those kinds of unwind that would be allowed with -C panic=abort, whether destructors run or not run would be a platform-specific detail, that users need to look up

Last update: Nov 15 2019 at 10:50UTC