[v2,3/3] Fix __libc_signal_block_all on sparc64
Commit Message
The a2e8aa0d9e shows two regressions on sparc64-linux-gnu:
nptl/tst-cancel-self-canceltype
nptl/tst-cancel5
This is not from the patch itself, but rather from an invalid
__NR_rt_sigprocmask issued by the loader:
rt_sigprocmask(SIG_UNBLOCK, [RTMIN RT_1], NULL, 8) = 0
rt_sigprocmask(0xffd07c60 /* SIG_??? */, ~[], 0x7feffd07d08, 8) = -1 EINVAL (Invalid argument)
Tracking the culprit it really seems a wrong code generation in the
INTERNAL_SYSCALL due the automatic sigset_t used on
__libc_signal_block_all:
return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &SIGALL_SET,
set, _NSIG / 8);
Where SIGALL_SET is defined as:
((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } })
Building the expanded __libc_signal_block_all on sparc64 with recent
compiler (gcc 8.3.1 and 9.1.1):
#include <signal>
int
_libc_signal_block_all (sigset_t *set)
{
INTERNAL_SYSCALL_DECL (err);
return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &SIGALL_SET,
set, _NSIG / 8);
}
It seems that the first argument (SIG_BLOCK) is not correctly set on
'o0' register:
__libc_signal_block_all:
save %sp, -304, %sp
add %fp, 1919, %o0
mov 128, %o2
sethi %hi(.LC0), %o1
call memcpy, 0
or %o1, %lo(.LC0), %o1
add %fp, 1919, %o1
mov %i0, %o2
mov 8, %o3
mov 103, %g1
ta 0x6d;
bcc,pt %xcc, 1f
mov 0, %g1
sub %g0, %o0, %o0
mov 1, %g1
1: sra %o0, 0, %i0
return %i7+8
nop
Where is I define SIGALL_SET outside INTERNAL_SYSCALL macro, gcc
correctly sets the expected kernel argument in correct register:
sethi %hi(.LC0), %o1
call memcpy, 0
or %o1, %lo(.LC0), %o1
-> mov 1, %o0
add %fp, 1919, %o1
This patch fixes it by moving both sigset_t that represent all signals
sets and the application set to constant data objects. This patch also
changes the return value of __libc_signal_block_all,
__libc_signal_block_app, and __libc_signal_restore_set to 'void'
since the function should not fail if input argument is NULL. Also,
for Linux the return value is not fully correct on some platforms due
the missing usage of INTERNAL_SYSCALL_ERROR_P / INTERNAL_SYSCALL_ERRNO
macros.
Checked on x86_64-linux-gnu, i686-linux-gnu, and sparc64-linux-gnu.
---
sysdeps/unix/sysv/linux/internal-signals.h | 37 ++++++++++++++--------
1 file changed, 24 insertions(+), 13 deletions(-)
Comments
On 05/12/2019 15:34, Adhemerval Zanella wrote:
> The a2e8aa0d9e shows two regressions on sparc64-linux-gnu:
>
> nptl/tst-cancel-self-canceltype
> nptl/tst-cancel5
It also fixes support/tst-support_capture_subprocess failures I have been
on sparcv9.
@@ -53,36 +53,47 @@ __clear_internal_signals (sigset_t *set)
__sigdelset (set, SIGSETXID);
}
-#define SIGALL_SET \
- ((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } })
+static const sigset_t sigall_set = {
+ .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 }
+};
+
+static const sigset_t sigapp_set = {
+#if ULONG_MAX == 0xffffffff
+ .__val = { [0] = ~0UL & ~(__sigmask (SIGCANCEL)),
+ [1] = ~0UL & ~(__sigmask (SIGSETXID)),
+ [2 ... _SIGSET_NWORDS-1] = ~0UL }
+#else
+ .__val = { [0] = ~0UL & ~(__sigmask (SIGCANCEL)
+ | __sigmask (SIGSETXID)),
+ [1 ... _SIGSET_NWORDS-1] = ~0UL }
+#endif
+};
/* Block all signals, including internal glibc ones. */
-static inline int
+static inline void
__libc_signal_block_all (sigset_t *set)
{
INTERNAL_SYSCALL_DECL (err);
- return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &SIGALL_SET,
- set, _NSIG / 8);
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, err, SIG_BLOCK, &sigall_set, set,
+ _NSIG / 8);
}
/* Block all application signals (excluding internal glibc ones). */
-static inline int
+static inline void
__libc_signal_block_app (sigset_t *set)
{
- sigset_t allset = SIGALL_SET;
- __clear_internal_signals (&allset);
INTERNAL_SYSCALL_DECL (err);
- return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_BLOCK, &allset, set,
- _NSIG / 8);
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, err, SIG_BLOCK, &sigapp_set, set,
+ _NSIG / 8);
}
/* Restore current process signal mask. */
-static inline int
+static inline void
__libc_signal_restore_set (const sigset_t *set)
{
INTERNAL_SYSCALL_DECL (err);
- return INTERNAL_SYSCALL (rt_sigprocmask, err, 4, SIG_SETMASK, set, NULL,
- _NSIG / 8);
+ INTERNAL_SYSCALL_CALL (rt_sigprocmask, err, SIG_SETMASK, set, NULL,
+ _NSIG / 8);
}
/* Used to communicate with signal handler. */