This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
[PATCH] Fix __libc_signal_block_all on sparc64
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: libc-alpha at sourceware dot org
- Date: Thu, 5 Dec 2019 11:35:26 -0300
- Subject: [PATCH] Fix __libc_signal_block_all on sparc64
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 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 sparc64-linux-gnu.
---
sysdeps/generic/internal-signals.h | 12 ++++++------
sysdeps/unix/sysv/linux/internal-signals.h | 19 ++++++++++---------
2 files changed, 16 insertions(+), 15 deletions(-)
diff --git a/sysdeps/generic/internal-signals.h b/sysdeps/generic/internal-signals.h
index a515e3e649..41c24dc4b3 100644
--- a/sysdeps/generic/internal-signals.h
+++ b/sysdeps/generic/internal-signals.h
@@ -34,28 +34,28 @@ __clear_internal_signals (sigset_t *set)
{
}
-static inline int
+static inline void
__libc_signal_block_all (sigset_t *set)
{
sigset_t allset;
__sigfillset (&allset);
- return __sigprocmask (SIG_BLOCK, &allset, set);
+ __sigprocmask (SIG_BLOCK, &allset, set);
}
-static inline int
+static inline void
__libc_signal_block_app (sigset_t *set)
{
sigset_t allset;
__sigfillset (&allset);
__clear_internal_signals (&allset);
- return __sigprocmask (SIG_BLOCK, &allset, set);
+ __sigprocmask (SIG_BLOCK, &allset, set);
}
/* Restore current process signal mask. */
-static inline int
+static inline void
__libc_signal_restore_set (const sigset_t *set)
{
- return __sigprocmask (SIG_SETMASK, set, NULL);
+ __sigprocmask (SIG_SETMASK, set, NULL);
}
diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h
index 01d8bf0a4c..0a5faf175f 100644
--- a/sysdeps/unix/sysv/linux/internal-signals.h
+++ b/sysdeps/unix/sysv/linux/internal-signals.h
@@ -57,32 +57,33 @@ __clear_internal_signals (sigset_t *set)
((__sigset_t) { .__val = {[0 ... _SIGSET_NWORDS-1 ] = -1 } })
/* Block all signals, including internal glibc ones. */
-static inline int
+static inline void
__libc_signal_block_all (sigset_t *set)
{
+ sigset_t allset = SIGALL_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, &allset, 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, &allset, 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. */
--
2.17.1