redesign sigsetjmp so that signal mask is restored after longjmp
authorRich Felker <dalias@aerifal.cx>
Sat, 18 Apr 2015 01:54:42 +0000 (21:54 -0400)
committerRich Felker <dalias@aerifal.cx>
Sat, 18 Apr 2015 01:54:42 +0000 (21:54 -0400)
the conventional way to implement sigsetjmp is to save the signal mask
then tail-call to setjmp; siglongjmp then restores the signal mask and
calls longjmp. the problem with this approach is that a signal already
pending, or arriving between unmasking of signals and restoration of
the saved stack pointer, will have its signal handler run on the stack
that was active before siglongjmp was called. this can lead to
unbounded stack usage when siglongjmp is used to leave a signal
handler.

in the new design, sigsetjmp saves its own return address inside the
extended part of the sigjmp_buf (outside the __jmp_buf part used by
setjmp) then calls setjmp to save a jmp_buf inside its own execution.
it then tail-calls to __sigsetjmp_tail, which uses the return value of
setjmp to determine whether to save the current signal mask or restore
a previously-saved mask.

as an added bonus, this design makes it so that siglongjmp and longjmp
are identical. this is useful because the __longjmp_chk function we
need to add for ABI-compatibility assumes siglongjmp and longjmp are
the same, but for different reasons -- it was designed assuming either
can access a flag just past the __jmp_buf indicating whether the
signal masked was saved, and act on that flag. however, early versions
of musl did not have space past the __jmp_buf for the non-sigjmp_buf
version of jmp_buf, so our setjmp cannot store such a flag without
risking clobbering memory on (very) old binaries.

12 files changed:
src/signal/aarch64/sigsetjmp.s
src/signal/arm/sigsetjmp.s
src/signal/i386/sigsetjmp.s
src/signal/microblaze/sigsetjmp.s
src/signal/mips/sigsetjmp.s
src/signal/or1k/sigsetjmp.s
src/signal/powerpc/sigsetjmp.s
src/signal/sh/sigsetjmp.s
src/signal/siglongjmp.c
src/signal/sigsetjmp_tail.c [new file with mode: 0644]
src/signal/x32/sigsetjmp.s
src/signal/x86_64/sigsetjmp.s

index e0f83f06929a38763fe1a47d07bc027ae53568b8..347d0bc02c8c39152f7aefa7f7f00c94a06a07ca 100644 (file)
@@ -4,16 +4,18 @@
 .type __sigsetjmp,%function
 sigsetjmp:
 __sigsetjmp:
-       str x1,[x0,#176]
        cbz x1,setjmp
 
-       // TODO errno?
-       // sigprocmask(SIG_SETMASK, 0, (sigset_t*)buf->__ss);
-       stp x0,x30,[sp,#-16]!
-       add x2,x0,#184
-       mov x1,#0
-       mov x0,#2
-       bl sigprocmask
-       ldp x0,x30,[sp],#16
+       str lr,[x0,#176]
+       str x19,[x0,#176+8+8]
+       mov x19,x0
 
-       b setjmp
+       bl setjmp
+
+       mov w1,w0
+       mov x0,x19
+       ldr lr,[x0,#176]
+       ldr x19,[x0,#176+8+8]
+
+.hidden __sigsetjmp_tail
+       b __sigsetjmp_tail
index 0e7bcd49e85981be0d1245896c1b94ba3c1a54d6..89c020b8eae30e22293ed4683cb5e30cc1ab703e 100644 (file)
@@ -4,13 +4,19 @@
 .type __sigsetjmp,%function
 sigsetjmp:
 __sigsetjmp:
-       str a2,[a1,#256]
-       tst a2,a2
+       tst r1,r1
        beq setjmp
-       push {a1,lr}
-       add a3,a1,#260
-       mov a2,#0
-       mov a1,#2
-       bl sigprocmask
-       pop {a1,lr}
-       b setjmp
+
+       str lr,[r0,#256]
+       str r4,[r0,#260+8]
+       mov r4,r0
+
+       bl setjmp
+
+       mov r1,r0
+       mov r0,r4
+       ldr lr,[r0,#256]
+       ldr r4,[r0,#260+8]
+
+.hidden __sigsetjmp_tail
+       b __sigsetjmp_tail
index 91c8c0486892b0fd6a13fcb0e610d2b546c20bd8..1d24b6f78f384d7cb2fab5698f7b8fb02c7142d3 100644 (file)
@@ -4,14 +4,22 @@
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-       mov 4(%esp),%eax
        mov 8(%esp),%ecx
-       mov %ecx,24(%eax)
        jecxz 1f
-       add $28,%eax
-       push %eax
-       push $0
-       push $2
-       call sigprocmask
-       add $12,%esp
+
+       mov 4(%esp),%eax
+       popl 24(%eax)
+       mov %ebx,28+8(%eax)
+       mov %eax,%ebx
+
+       call setjmp
+
+       pushl 24(%ebx)
+       mov %ebx,4(%esp)
+       mov %eax,8(%esp)
+       mov 28+8(%ebx),%ebx
+
+.hidden __sigsetjmp_tail
+       jmp __sigsetjmp_tail
+
 1:     jmp setjmp
index 2a23d147ed0263500534b5f1c39508cd2c1aa70b..8430c9c4bffc6d0cf436c9963bc26c28b08f0abe 100644 (file)
@@ -4,18 +4,18 @@
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-       swi     r6, r5, 72
-       beqi    r6, setjmp@PLT
+       beqi r6, setjmp@PLT
 
-       addi    r1, r1, -32
-       swi     r15, r1, 28
-       swi     r5, r1, 24
-       addi    r7, r5, 76
-       add     r6, r0, r0
-       brlid   r15, sigprocmask@PLT
-       ori     r5, r0, 2
+       swi r15,r5,72
+       swi r19,r5,72+4+8
 
-       lwi     r15, r1, 28
-       lwi     r5, r1, 24
-       brid    setjmp@PLT
-       addi    r1, r1, 32
+       brlid r15,setjmp@PLT
+        ori r19,r5,0
+
+       ori r6,r3,0
+       ori r5,r19,0
+       lwi r15,r5,72
+       lwi r19,r5,72+4+8
+
+.hidden __sigsetjmp_tail
+       bri __sigsetjmp_tail
index 133ca777acf406e2ea0a00f5396f6c4311f2cfdf..74b65ff68f2593cb7f4c0c2143f7813ecbd04db6 100644 (file)
@@ -9,22 +9,25 @@ __sigsetjmp:
        lui $gp, %hi(_gp_disp)
        addiu $gp, %lo(_gp_disp)
        beq $5, $0, 1f
-       addu $gp, $gp, $25
-       subu $sp, $sp, 32
-       sw $4, 20($sp)
-       sw $ra, 24($sp)
-       sw $gp, 28($sp)
-       addu $6, $4, 108
-       li $5, 0
-       li $4, 1
-       sw $4, -4($6)
-       lw $25, %call16(sigprocmask)($gp)
+        addu $gp, $gp, $25
+
+       sw $ra, 104($4)
+       sw $16, 104+4+16($4)
+
+       lw $25, %call16(setjmp)($gp)
        jalr $25
-       nop
-       lw $gp, 28($sp)
-       lw $ra, 24($sp)
-       lw $4, 20($sp)
-       addu $sp, $sp, 32
+        move $16, $4
+
+       move $5,$2
+       move $4,$16
+       lw $ra, 104($4)
+       lw $16, 104+4+16($4)
+
+.hidden __sigsetjmp_tail
+       lw $25, %call16(__sigsetjmp_tail)($gp)
+       jr $25
+        nop
+
 1:     lw $25, %call16(setjmp)($gp)
        jr $25
-       nop
+        nop
index 70a292236fd098d23e223c5284ec6d937dee59e3..350c00e212e86f5e3b9598cdf6ad04b1127eadae 100644 (file)
@@ -6,17 +6,18 @@ sigsetjmp:
 __sigsetjmp:
        l.sfeq  r4, r0
        l.bf    plt(setjmp)
-        l.sw   52(r3), r4      /* buf->__fl = save */
 
-       l.addi  r1, r1, -8
-       l.sw    0(r1), r9
-       l.sw    4(r1), r3
-       l.addi  r5, r3, 56      /* buf->__ss */
-       l.add   r4, r0, r0
-       l.jal   plt(sigprocmask)
-        l.ori  r3, r0, 2       /* SIG_SETMASK */
+       l.sw    52(r3), r9
+       l.sw    52+4+8(r3), r20
 
-       l.lwz   r9, 0(r1)
-       l.lwz   r3, 4(r1)
-       l.j     plt(setjmp)
-        l.addi r1, r1, 8
+       l.jal   plt(setjmp)
+        l.ori   r20, r3, 0
+
+       l.ori r4, r11, 0
+       l.ori r3, r20, 0
+
+       l.lwz   r9, 52(r3)
+
+.hidden __sigsetjmp_tail
+       l.j     plt(__sigsetjmp_tail)
+        l.lwz   r20, 52+4+8(r3)
index 461b73721e0715021b4255e6e1ff8e54926a7d94..78acf5907121a93161d5e33f797fc7ded552c5f2 100644 (file)
@@ -4,35 +4,23 @@
        .type __sigsetjmp,%function
 sigsetjmp:
 __sigsetjmp:
-       #int sigsetjmp(sigjmp_buf buf, int save)
-       #               r3              r4
-       #0) store save into buf->__fl
-       stw 4, 448(3)
-       #1) compare save with 0
        cmpwi cr7, 4, 0
-       #2) if its 0, goto setjmp code
        beq- cr7, 1f
-       #3) else: we must call pthread_sigmask(SIG_SETMASK, 0, (sigset_t *)buf->__ss);
-       # store non-volatile regs 30, 31 into the setjmp buf
-       stw 30, 0(3)
-       stw 31, 4(3)
-       # use them to store the pointer to the jmpbuf and the link reg
-       mr 30, 3
-       mflr 31
-       
-       # put pointer to ss buf into r5 (3rd arg)
-       addi 5, 3, 452
-       # put "2" i.e. SIG_SETMASK in r3
-       li 3, 2
-       li 4, 0
-       bl pthread_sigmask
-       
-       #restore jmpbuf pointer and link reg
-       mr 3, 30
-       mtlr 31
-       #resore non-volatile regs
-       lwz 30, 0(3)
-       lwz 31, 4(3)
 
-1:
-       b setjmp
+       mflr 5
+       stw 5, 448(3)
+       stw 16, 448+4+8(3)
+       mr 16, 3
+
+       bl setjmp
+
+       mr 4, 3
+       mr 3, 16
+       lwz 5, 448(3)
+       mtlr 5
+       lwz 16, 448+4+8(3)
+
+.hidden __sigsetjmp_tail
+       b __sigsetjmp_tail
+
+1:     b setjmp
index 7951f07ea96e5058473726a5a9df04a0c42a18c6..7d1e7c95f1019d46b1fdcf0a77bbd16bec6dd1cd 100644 (file)
@@ -4,27 +4,37 @@
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-       mov.l r5, @(36,r4)
        tst r5, r5
-       bf  2f
+       bt 9f
 
-       sts.l pr, @-r15
-       mov.l r4, @-r15
        mov r4, r6
-       add #40, r6
-       mov #0, r5
-       mov #2, r4
-       mov.l L1, r0
-       bsrf  r0
-        nop
-1:     mov.l @r15+, r4
-       lds.l @r15+, pr
+       add #52, r6
+       sts pr, r0
+       mov.l r0, @r6
+       mov.l r8, @(4+8,r6)
+
+       mov.l 1f, r0
+2:     bsrf r0
+        mov r4, r8
+
+       mov r0, r5
+       mov r8, r4
+       mov r4, r6
+       add #52, r6
+
+       mov.l @r6, r0
+       lds r0, pr
+
+       mov.l 3f, r0
+4:     braf r0
+        mov.l @(4+8,r4), r8
 
-2:     mov.l L2, r0
-       braf  r0
+9:     mov.l 5f, r0
+6:     braf r0
         nop
-3:
 
 .align 2
-L1:    .long pthread_sigmask@PLT-(1b-.)
-L2:    .long setjmp@PLT-(3b-.)
+1:     .long setjmp@PLT-(2b+4-.)
+.hidden __sigsetjmp_tail
+3:     .long __sigsetjmp_tail@PLT-(4b+4-.)
+5:     .long setjmp@PLT-(6b+4-.)
index b644cebb98f60b4526919a9637ed5803426e67a4..bc317acce93176a939f6de518cbe67d81284bdfd 100644 (file)
@@ -5,6 +5,5 @@
 
 _Noreturn void siglongjmp(sigjmp_buf buf, int ret)
 {
-       if (buf->__fl) __restore_sigs(buf->__ss);
        longjmp(buf, ret);
 }
diff --git a/src/signal/sigsetjmp_tail.c b/src/signal/sigsetjmp_tail.c
new file mode 100644 (file)
index 0000000..487ad8c
--- /dev/null
@@ -0,0 +1,13 @@
+#include <setjmp.h>
+#include <signal.h>
+#include "syscall.h"
+
+#ifdef SHARED
+__attribute__((__visibility__("hidden")))
+#endif
+int __sigsetjmp_tail(sigjmp_buf jb, int ret)
+{
+       void *p = jb->__ss;
+       __syscall(SYS_rt_sigprocmask, SIG_SETMASK, ret?p:0, ret?0:p, _NSIG/8);
+       return ret;
+}
index 17436f02cea41752d6b25bdd8e874902745fd261..d354d6802a9e32108c7bdbd2ea6e65cf6d6beaf5 100644 (file)
@@ -1,17 +1,24 @@
-/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
 .global sigsetjmp
 .global __sigsetjmp
 .type sigsetjmp,@function
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-       andl %esi,%esi
-       movq %rsi,64(%rdi)
+       test %esi,%esi
        jz 1f
-       pushq %rdi
-       leaq 72(%rdi),%rdx
-       xorl %esi,%esi
-       movl $2,%edi
-       call sigprocmask
-       popq %rdi
+
+       popq 64(%rdi)
+       mov %rbx,72+8(%rdi)
+       mov %rdi,%rbx
+
+       call setjmp
+
+       pushq 64(%rbx)
+       mov %rbx,%rdi
+       mov %eax,%esi
+       mov 72+8(%rbx),%rbx
+
+.hidden __sigsetjmp_tail
+       jmp __sigsetjmp_tail
+
 1:     jmp setjmp
index 17436f02cea41752d6b25bdd8e874902745fd261..d354d6802a9e32108c7bdbd2ea6e65cf6d6beaf5 100644 (file)
@@ -1,17 +1,24 @@
-/* Copyright 2011-2012 Nicholas J. Kain, licensed under standard MIT license */
 .global sigsetjmp
 .global __sigsetjmp
 .type sigsetjmp,@function
 .type __sigsetjmp,@function
 sigsetjmp:
 __sigsetjmp:
-       andl %esi,%esi
-       movq %rsi,64(%rdi)
+       test %esi,%esi
        jz 1f
-       pushq %rdi
-       leaq 72(%rdi),%rdx
-       xorl %esi,%esi
-       movl $2,%edi
-       call sigprocmask
-       popq %rdi
+
+       popq 64(%rdi)
+       mov %rbx,72+8(%rdi)
+       mov %rdi,%rbx
+
+       call setjmp
+
+       pushq 64(%rbx)
+       mov %rbx,%rdi
+       mov %eax,%esi
+       mov 72+8(%rbx),%rbx
+
+.hidden __sigsetjmp_tail
+       jmp __sigsetjmp_tail
+
 1:     jmp setjmp