diff --git a/libc/arch-x86_64/bionic/setjmp.S b/libc/arch-x86_64/bionic/setjmp.S index a8f614ffb..28981fad0 100644 --- a/libc/arch-x86_64/bionic/setjmp.S +++ b/libc/arch-x86_64/bionic/setjmp.S @@ -48,6 +48,7 @@ #define _JB_PC 7 #define _JB_SIGFLAG 8 #define _JB_SIGMASK 9 +#define _JB_SIGMASK_RT 10 // sigprocmask will write here too. ENTRY(setjmp) movl $1,%esi @@ -62,18 +63,19 @@ END(_setjmp) // int sigsetjmp(sigjmp_buf env, int save_signal_mask); ENTRY(sigsetjmp) // Record whether or not we're saving the signal mask. - movl %esi,(_JB_SIGFLAG * 8)(%rdi) + movl %esi,(_JB_SIGFLAG * 8)(%rdi) // Do we need to save the signal mask? testl %esi,%esi jz 2f - // Save the signal mask. - pushq %rdi - xorq %rdi,%rdi - call PIC_PLT(sigblock) - popq %rdi - movq %rax,(_JB_SIGMASK * 8)(%rdi) + // Save current signal mask. + pushq %rdi // Push 'env'. + // The 'how' argument is ignored if new_mask is NULL. + xorq %rsi,%rsi // NULL. + leaq (_JB_SIGMASK * 8)(%rdi),%rdx // old_mask. + call PIC_PLT(sigprocmask) + popq %rdi // Pop 'env'. 2: // Save the callee-save registers. @@ -97,12 +99,14 @@ ENTRY(siglongjmp) pushq %rsi // Push 'value'. // Do we need to restore the signal mask? - cmpl $0, (_JB_SIGFLAG * 8)(%rdi) + cmpl $0,(_JB_SIGFLAG * 8)(%rdi) jz 2f // Restore the signal mask. - movq (_JB_SIGMASK * 8)(%rdi),%rdi - call PIC_PLT(sigsetmask) + movq $2,%rdi // SIG_SETMASK. + leaq (_JB_SIGMASK * 8)(%r12),%rsi // new_mask. + xorq %rdx,%rdx // NULL. + call PIC_PLT(sigprocmask) 2: popq %rax // Pop 'value'. diff --git a/tests/setjmp_test.cpp b/tests/setjmp_test.cpp index 2df0135d9..2ea01b32d 100644 --- a/tests/setjmp_test.cpp +++ b/tests/setjmp_test.cpp @@ -63,17 +63,29 @@ TEST(setjmp, sigsetjmp_1_smoke) { } } -static sigset_t SigSetOf(int signal) { +static sigset_t SigSetOf(int signal, int rt_signal = 0) { sigset_t ss; sigemptyset(&ss); sigaddset(&ss, signal); + if (rt_signal != 0) { + sigaddset(&ss, rt_signal); + } return ss; } +void AssertSigmaskEquals(const sigset_t& expected) { + sigset_t actual; + sigprocmask(0 /* ignored */, NULL, &actual); + size_t end = sizeof(sigset_t) * 8; + for (size_t i = 1; i <= end; ++i) { + EXPECT_EQ(sigismember(&expected, i), sigismember(&actual, i)) << i; + } +} + TEST(setjmp, _setjmp_signal_mask) { // _setjmp/_longjmp do not save/restore the signal mask. - sigset_t ss1(SigSetOf(SIGUSR1)); - sigset_t ss2(SigSetOf(SIGUSR2)); + sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8)); + sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9)); sigset_t original_set; sigprocmask(SIG_SETMASK, &ss1, &original_set); jmp_buf jb; @@ -82,9 +94,7 @@ TEST(setjmp, _setjmp_signal_mask) { _longjmp(jb, 1); FAIL(); // Unreachable. } else { - sigset_t ss; - sigprocmask(SIG_SETMASK, NULL, &ss); - EXPECT_TRUE(sigismember(&ss, SIGUSR2)); + AssertSigmaskEquals(ss2); } sigprocmask(SIG_SETMASK, &original_set, NULL); } @@ -93,8 +103,8 @@ TEST(setjmp, setjmp_signal_mask) { // setjmp/longjmp do save/restore the signal mask on bionic, but not on glibc. // This is a BSD versus System V historical accident. POSIX leaves the // behavior unspecified, so any code that cares needs to use sigsetjmp. - sigset_t ss1(SigSetOf(SIGUSR1)); - sigset_t ss2(SigSetOf(SIGUSR2)); + sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8)); + sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9)); sigset_t original_set; sigprocmask(SIG_SETMASK, &ss1, &original_set); jmp_buf jb; @@ -103,14 +113,12 @@ TEST(setjmp, setjmp_signal_mask) { longjmp(jb, 1); FAIL(); // Unreachable. } else { - sigset_t ss; - sigprocmask(SIG_SETMASK, NULL, &ss); #if defined(__BIONIC__) // bionic behaves like BSD and does save/restore the signal mask. - EXPECT_TRUE(sigismember(&ss, SIGUSR1)); + AssertSigmaskEquals(ss1); #else // glibc behaves like System V and doesn't save/restore the signal mask. - EXPECT_TRUE(sigismember(&ss, SIGUSR2)); + AssertSigmaskEquals(ss2); #endif } sigprocmask(SIG_SETMASK, &original_set, NULL); @@ -118,8 +126,8 @@ TEST(setjmp, setjmp_signal_mask) { TEST(setjmp, sigsetjmp_0_signal_mask) { // sigsetjmp(0)/siglongjmp do not save/restore the signal mask. - sigset_t ss1(SigSetOf(SIGUSR1)); - sigset_t ss2(SigSetOf(SIGUSR2)); + sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8)); + sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9)); sigset_t original_set; sigprocmask(SIG_SETMASK, &ss1, &original_set); sigjmp_buf sjb; @@ -128,17 +136,15 @@ TEST(setjmp, sigsetjmp_0_signal_mask) { siglongjmp(sjb, 1); FAIL(); // Unreachable. } else { - sigset_t ss; - sigprocmask(SIG_SETMASK, NULL, &ss); - EXPECT_TRUE(sigismember(&ss, SIGUSR2)); + AssertSigmaskEquals(ss2); } sigprocmask(SIG_SETMASK, &original_set, NULL); } TEST(setjmp, sigsetjmp_1_signal_mask) { // sigsetjmp(1)/siglongjmp does save/restore the signal mask. - sigset_t ss1(SigSetOf(SIGUSR1)); - sigset_t ss2(SigSetOf(SIGUSR2)); + sigset_t ss1(SigSetOf(SIGUSR1, SIGRTMIN + 8)); + sigset_t ss2(SigSetOf(SIGUSR2, SIGRTMIN + 9)); sigset_t original_set; sigprocmask(SIG_SETMASK, &ss1, &original_set); sigjmp_buf sjb; @@ -147,9 +153,7 @@ TEST(setjmp, sigsetjmp_1_signal_mask) { siglongjmp(sjb, 1); FAIL(); // Unreachable. } else { - sigset_t ss; - sigprocmask(SIG_SETMASK, NULL, &ss); - EXPECT_TRUE(sigismember(&ss, SIGUSR1)); + AssertSigmaskEquals(ss1); } sigprocmask(SIG_SETMASK, &original_set, NULL); }