Comment 6 for bug 599862

Revision history for this message
Dave Martin (dave-martin-arm) wrote :

OK, the source of scariness seems to be in pth_mctx.c which does some evil-looking things in order to implement userspace threading.

In order to switch threads with an accompanying switch of stack, setjmp() is called from inside a signal handler which has an alternate signal stack set up. [1]

eglibc barfs when the corresponding longjmp() from the main thread tries to jump back into the signal handler after the signal handler returns (!) The maintainers claim this is portable within POSIX, but I'm less than convinced. POSIX is somewhat vague about the circumstances in which it's safe to longjmp() out of a signal handler, to say nothing of what happens on a modern kernel with interruptible system calls etc. ..., and expressly prohibits longjmp'ing back into a function which has returned. Behaviour for siglongjmp in this situation appears to be undefined, but my conclusion is that this is not supposed to be supported either [2] If so, and if I've understood the implications correctly, this would invalidate any claim of strict portability in pth.

I haven't read the full rationale [3] but it contains some interesting caveats:
"Even on operating systems which have working POSIX functions, our approach may theoretically still not work, because longjmp [...] [may branch] to error-handling code if it detects that the caller tries to jump up the stack, i.e., into a stack frame which has already returned"

We may be hitting just such a check here.

Notwithstanding this, the contents of the jmp_buf otherwise looks sane when the failing longjmp call occurs. See the attached debug log: the sp and pc values saved in the jmp_buf for pth_mctx_set_trampoline at pth_mctx.c:394 appear to match those in the jmp_buf passed to longjmp at pth_mctx.c:362

[1] see http://bazaar.launchpad.net/~ubuntu-branches/ubuntu/maverick/pth/maverick/annotate/head%3A/pth_mctx.c

[2] See IEEE Std 1003.1-2008 (System Interfaces: longjmp) http://www.opengroup.org/onlinepubs/9699919799/

"The longjmp() function shall restore the environment saved by the most recent invocation of setjmp() in the same thread, with the corresponding jmp_buf argument. If [...] the function containing the invocation of setjmp() has terminated execution in the interim [...] the behavior is undefined."

(This specification derives directly from ISO C)

[3] "Portable Multithreading - The Signal Stack Trick For User-Space Thread Creation", Ralf S. Engelschall: http://bazaar.launchpad.net/%7Eubuntu-branches/ubuntu/maverick/pth/maverick/annotate/head%3A/rse-pmt.ps