Browse Source

Wohoo! David McCullough found the bug! His comments follow:

    I had a look at it and you won't believe it was always broken.

    I'll try and explain it,  let me know if it doesn't make sense.

    * ash calls setjmp,  which messes with the stack to look like it has
      two args instead of one and then jmps (actually falls) into
    sigsetjmp.

      BUG

    * sigsetjmp then saves the registers and "jumps" to __sigset_save,  a C
      function.

    BUG1 - because the caller pops its args off the stack,  a program that
	   changes it's number of args is broken because the caller will
    not
	       pop the correct number of args.

    I think that jumping from the sigsetjmp asm to the 'C' code is unsafe
    but I can't think of an example.  Anyway,  I have attached what I think
    is
    a working fix.

    The reason this worked without -fomit-frame-pointer is that the
    _sigset_save 'C' code would restore the stack pointer from %ebp (the
    frame
    pointer) and because none of the asm had moded it,  when we returned
    from
    __sigset_save the stack was back to it's correct position for 1
    argument
    despite our best attempts to stuff it up ;-)
Eric Andersen 23 years ago
parent
commit
8a309c2fde
1 changed files with 20 additions and 12 deletions
  1. 20 12
      libc/sysdeps/linux/i386/setjmp.S

+ 20 - 12
libc/sysdeps/linux/i386/setjmp.S

@@ -21,16 +21,6 @@
 #define _SETJMP_H
 #include <bits/setjmp.h>
 
-.globl _setjmp;
-.type	 _setjmp,@function
-.align 4;                                                               \
-_setjmp:
-	popl %eax		/* Pop return address.  */
-	popl %ecx		/* Pop jmp_buf.  */
-	pushl $0		/* Push zero argument.  */
-	pushl %ecx		/* Push jmp_buf.  */
-	pushl %eax		/* Push back return address.  */
-
 .globl __sigsetjmp;
 .type	 __sigsetjmp,@function
 .align 4;                                                               \
@@ -46,6 +36,9 @@ __sigsetjmp:
 	movl 0(%esp), %ecx	/* Save PC we are returning to now.  */
      	movl %ecx, (JB_PC*4)(%eax)
 
+	pushl 0x8(%esp) /* save mask */
+	pushl 0x8(%esp) /* jump buf */
+
 	/* Make a tail call to __sigjmp_save; it takes the same args.  */
 #if defined(PIC)
 	/* We cannot use the PLT, because it requires that %ebx be set, but
@@ -57,8 +50,23 @@ Lhere:
 	popl %ecx
 	addl $_GLOBAL_OFFSET_TABLE_+[.-Lhere], %ecx
 	movl (__sigjmp_save)(%ecx), %ecx
-	jmp *%ecx
+	call *%ecx
 #else
-	jmp __sigjmp_save
+	call __sigjmp_save
 #endif
+
+	add  $8, %esp
+	ret
 .size __sigsetjmp,.-__sigsetjmp;
+
+.globl _setjmp;
+.type	 _setjmp,@function
+.align 4;                                                               \
+_setjmp:
+	pushl $0		/* Push zero argument.  */
+	pushl 0x8(%esp)	/* Push jmp_buf.  */
+	call  __sigsetjmp
+	add  $8, %esp
+	ret
+.size _setjmp,.-_setjmp;
+