Mark Mendell <mendell@ca.ibm.com> reports: Hardware Environment: p690 (actually any 64 bit PPC) Software Environment: RHEL 3 QU2 and SLES9 RC5 Steps to Reproduce: 1. t.c: #include <setjmp.h> jmp_buf buf1; jmp_buf buf2; int *p; int n_x = 6; static int g_counter = 0; #define g(x) \ { \ int a[n_x], i; \ g_counter++; \ p = &a[0]; \ if( g_counter < 5 ) longjmp(buf1, 2); \ else if( g_counter == 5 ) longjmp(buf1, 101); \ else { setjmp(buf2); longjmp(buf1, 101); } \ } int f(int n) { static int counter = 0; int i; if( setjmp(buf1) != 101 ) { g(6); } if( counter == 0 ) { counter++; g(6); } if( counter == 1 ) { counter++; longjmp(buf2, 2); } return n; } int main( ) { f(6); } 2. gcc -m64 t.c; a.out Actual Results: Segmentation fault Expected Results: <none> Additional Information: This is a previously seen problem with longjmp on AIX. It is essential that longjmp store gpr2 at 40(sp) before returning to the user program. This is because the call to setjmp is probably followed by a reload of gpr2. If an alloca (or VLA in C99) has been done between the setjmp and the longjmp, then the saved TOC at 40(sp) may not be set. The easiest fix is to add 'std r2,40(r1)' to the end of longjmp just before returning to the user code. This was actually seen with a similar program compiled with xlc at -O4, but I rewrote it for general distribution.
This test messes with the stack pointer by dynamically allocating automatic storage. So by the time longjmp (buf2, 2) the orginal TOC save area has been clobbered by the stack extention. Either way if the solution is to have longjmp restore the TOC save area __longjmp must abtain the orginal TOC value before the call to setjmp. In this (simple) case the appl calls [bsd]_setjmp() which transfers to __setjmp. Both are in libc.so. So by the time __setjmp() gets control libc.so's TOC is already loaded. In this case we need to reach back into the callers frame and retrieve the callers TOC from the TOC save area. But in the static case the TOC is not saved and has not changed. In GLIBC sysdeps/powerpc/powerpc64/setjmp.S is built 4 times (static, shared, profiled, and a special version (rtld-setjmp) for the dynamic linker. In the SHARED case (libc.so), external calls to setjmp will save the TOC on the stack, but internal libc calls will not. So the trick is to do the correct thing for each case.
Patch submitted to libc-alpha. http://sources.redhat.com/ml/libc-alpha/2004-07/msg00048.html
Subject: Bug 269 CVSROOT: /cvs/glibc Module name: libc Changes by: drepper@sources.redhat.com 2004-07-16 23:08:13 Added files: setjmp : bug269-setjmp.c Log message: Test for setjmp problem on ppc64 (bz 269). Patches: http://sources.redhat.com/cgi-bin/cvsweb.cgi/libc/setjmp/bug269-setjmp.c.diff?cvsroot=glibc&r1=NONE&r2=1.1
Fixed in CVS.