From 297d9cd07d7ea9b541fb13bffe418c8b2a8c3aa6 Mon Sep 17 00:00:00 2001 From: Paul Pluzhnikov Date: Mon, 14 Nov 2011 23:45:09 -0800 Subject: [PATCH] Fix for failing test-setjmp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit On Mon, Nov 14, 2011 at 5:02 PM, Paul Pluzhnikov wrote: > P.S. test-setjmp is failing for me (before or after the patch). > When I enable assertions (to confirm my new assertions are correct), I see: > >  lt-test-setjmp: ../../src/dwarf/Gparser.c:754: apply_reg_state: \ >    Assertion `rs->reg[17].where == DWARF_WHERE_EXPR' failed. > > which likely explains that failure. The problem is actually two-fold: First, the loops in {sig,}longjmp.c are "do { ... } while (unw_step() >= 0);" But unw_step() returns 0 on reaching the end of the chain (_start), and the loop should stop there. The second problem is that with this commit: http://repo.or.cz/w/glibc.git/commitdiff/c67da0b50e3d20f89d7bb352cd67dcf66d808e50 glibc obfuscates value of SP in jmp_buf, so we might as well just give up. Patch attached. Thanks, -- Paul Pluzhnikov --- src/setjmp/longjmp.c | 18 +++++++++++++++++- src/setjmp/siglongjmp.c | 18 +++++++++++++++++- 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/setjmp/longjmp.c b/src/setjmp/longjmp.c index d056b1f0..00a58c2c 100644 --- a/src/setjmp/longjmp.c +++ b/src/setjmp/longjmp.c @@ -35,6 +35,20 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ #include "jmpbuf.h" #include "setjmp_i.h" +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 4) + +/* Starting with glibc-2.4, {sig,}setjmp in GLIBC obfuscates the + register values in jmp_buf by XORing them with a "random" + canary value. + + This makes it impossible to implement longjmp, as we + can never match wp[JB_SP], unless we decode the canary first. + + Doing so is possible, but doesn't appear to be worth the trouble, + so we simply defer to glibc longjmp here. */ + +#else + void _longjmp (jmp_buf env, int val) { @@ -75,7 +89,7 @@ _longjmp (jmp_buf env, int val) abort (); } - while (unw_step (&c) >= 0); + while (unw_step (&c) > 0); abort (); } @@ -90,4 +104,6 @@ longjmp (jmp_buf env, int val) _longjmp (env, val); } +#endif /* __GLIBC__ */ + #endif diff --git a/src/setjmp/siglongjmp.c b/src/setjmp/siglongjmp.c index da757e3c..bfe148b1 100644 --- a/src/setjmp/siglongjmp.c +++ b/src/setjmp/siglongjmp.c @@ -35,6 +35,20 @@ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ # define _NSIG (_SIG_MAXSIG - 1) #endif +#if defined(__GLIBC__) && __GLIBC_PREREQ(2, 4) + +/* Starting with glibc-2.4, {sig,}setjmp in GLIBC obfuscates the + register values in jmp_buf by XORing them with a "random" + canary value. + + This makes it impossible to implement longjmp, as we + can never match wp[JB_SP], unless we decode the canary first. + + Doing so is possible, but doesn't appear to be worth the trouble, + so we simply defer to glibc siglongjmp here. */ + +#else + void siglongjmp (sigjmp_buf env, int val) { @@ -96,7 +110,9 @@ siglongjmp (sigjmp_buf env, int val) abort (); } - while (unw_step (&c) >= 0); + while (unw_step (&c) > 0); abort (); } + +#endif /* __GLIBC__ */