[uClibc]subtle bug in arm version of setjmp/longjmp

Vadim Lebedev vadim at 7chips.com
Sat Feb 22 16:04:54 UTC 2003


Hello i think i've descovered a serious buf in the arm version of setjmp/longjmp

when configured without float support or wth soft float support

here is the code setjmp.S part:
====================================
.globl __sigsetjmp;
.type __sigsetjmp,%function
.align 4;
__sigsetjmp:
 /* Save registers */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
 sfmea   f4, 4, [r0]!
#endif
 stmia   r0, {v1-v6, sl, fp, sp, lr}

 /* Restore pointer to jmp_buf */
 sub     r0, r0, #48

 /* Make a tail call to __sigjmp_save; it takes the same args.  */
 B __sigjmp_save (PLT)
.size __sigsetjmp,.-__sigsetjmp;
============================

On entry r0 points to the sigjmp_env
with HW float support the cpu regs are stored after FP context (48 bytes) 

but when #if result is false
the cpu regs are stored at the beginnig of the buffer AND the sub instruction adjust r0 to point 48 bytes
BEFORE the beginning of the buffer,  so when sigjmp_save is called it stores signal mask info
not where are they expected but 48 bytes earlier.

in the longjmp.S we see:
==========================
.globl __longjmp;
.type __longjmp,%function
.align 4;
__longjmp:
 mov ip, r0  /* save jmp_buf pointer */
 
 movs r0, r1  /* get the return value in place */
 moveq r0, #1  /* can't let setjmp() return zero! */

#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
 lfmfd f4, 4, [ip] ! /* load the floating point regs */
#endif 

 ldmia     ip ,  {v1-v6, sl, fp, sp, pc}
.size __longjmp,.-__longjmp;
===========================
so if HW FP is enabled the cpu regs are restored from area after FP regs,  otherwise they are restored
from the beginning of the buffer

This matches well the setjmp.S stuff so the progams using the calls works however signal saving ad restoring
part is completely screwed because __sigjmp_save, stored signal mask in wrong place.

the code which use __JMPBUF_UNWINDS macro is also screwed becuase it exepcts to find stack ptr value
at jmp_buf[20] but without HW FP it is stored in  jmp_buf[20 - 48/4]

Suggested fix would be:
#setjmp.S
=======================
__sigsetjmp:
 /* Save registers */
#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
 sfmea   f4, 4, [r0]!
#else
 /* skip past FP regs area */  
 add  r0, r0, #48
#endif
 stmia   r0, {v1-v6, sl, fp, sp, lr}

 /* Restore pointer to jmp_buf */
 sub     r0, r0, #48

 /* Make a tail call to __sigjmp_save; it takes the same args.  */
 B __sigjmp_save (PLT)
.size __sigsetjmp,.-__sigsetjmp;

==============================
#longjmp.S
.globl __longjmp;
.type __longjmp,%function
.align 4;
__longjmp:
 mov ip, r0  /* save jmp_buf pointer */
 
 movs r0, r1  /* get the return value in place */
 moveq r0, #1  /* can't let setjmp() return zero! */

#if defined __UCLIBC_HAS_FLOATS__ && ! defined __UCLIBC_HAS_SOFT_FLOAT__
 lfmfd f4, 4, [ip] ! /* load the floating point regs */
#else
 /* skip past FP regs area */  
 add  ip, ip, #48
#endif

 ldmia     ip ,  {v1-v6, sl, fp, sp, pc}
.size __longjmp,.-__longjmp;



Best regard
Vadim


 


 





-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.busybox.net/pipermail/uclibc/attachments/20030222/2eeff9de/attachment-0001.htm 


More information about the uClibc mailing list