about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-04-23 10:58:01 -0300
committerAdhemerval Zanella <adhemerval.zanella@linaro.org>2020-07-07 14:10:58 -0300
commitf26d456b98abf02b3ff92f1a3c0d4473b7ffd85c (patch)
treee61f7a38a3f7ce9b8394d1ce8001cf6a3a9dc33e
parentf13d260190d47bd38c0ae939080001e7bb58bd04 (diff)
downloadglibc-f26d456b98abf02b3ff92f1a3c0d4473b7ffd85c.tar.gz
glibc-f26d456b98abf02b3ff92f1a3c0d4473b7ffd85c.tar.xz
glibc-f26d456b98abf02b3ff92f1a3c0d4473b7ffd85c.zip
linux: Fix __NSIG_WORDS and add __NSIG_BYTES
The __NSIG_WORDS value is based on minimum number of words to hold
the maximum number of signals supported by the architecture.

This patch also adds __NSIG_BYTES, which is the number of bytes
required to represent the supported number of signals.  It is used in
syscalls which takes a sigset_t.

Checked on x86_64-linux-gnu and i686-linux-gnu.

Tested-by: Carlos O'Donell <carlos@redhat.com>
Reviewed-by: Carlos O'Donell <carlos@redhat.com>
-rw-r--r--include/signal.h2
-rw-r--r--nptl/nptl-init.c2
-rw-r--r--nptl/pthread_sigmask.c2
-rw-r--r--sysdeps/unix/sysv/linux/aio_misc.h9
-rw-r--r--sysdeps/unix/sysv/linux/epoll_pwait.c2
-rw-r--r--sysdeps/unix/sysv/linux/internal-signals.h10
-rw-r--r--sysdeps/unix/sysv/linux/ppoll.c7
-rw-r--r--sysdeps/unix/sysv/linux/pselect.c2
-rw-r--r--sysdeps/unix/sysv/linux/sigaction.c3
-rw-r--r--sysdeps/unix/sysv/linux/signalfd.c2
-rw-r--r--sysdeps/unix/sysv/linux/sigpending.c2
-rw-r--r--sysdeps/unix/sysv/linux/sigsetops.h18
-rw-r--r--sysdeps/unix/sysv/linux/sigsuspend.c2
-rw-r--r--sysdeps/unix/sysv/linux/sigtimedwait.c3
-rw-r--r--sysdeps/unix/sysv/linux/x86/setjmpP.h5
15 files changed, 43 insertions, 28 deletions
diff --git a/include/signal.h b/include/signal.h
index aa68f45886..3d6315b741 100644
--- a/include/signal.h
+++ b/include/signal.h
@@ -2,6 +2,8 @@
 # include <signal/signal.h>
 
 # ifndef _ISOMAC
+#  include <sigsetops.h>
+
 libc_hidden_proto (sigemptyset)
 libc_hidden_proto (sigfillset)
 libc_hidden_proto (sigaddset)
diff --git a/nptl/nptl-init.c b/nptl/nptl-init.c
index d4cf20e3d1..95c60a524a 100644
--- a/nptl/nptl-init.c
+++ b/nptl/nptl-init.c
@@ -281,7 +281,7 @@ __pthread_initialize_minimal_internal (void)
   __sigaddset (&sa.sa_mask, SIGCANCEL);
   __sigaddset (&sa.sa_mask, SIGSETXID);
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &sa.sa_mask,
-			 NULL, _NSIG / 8);
+			 NULL, __NSIG_BYTES);
 
   /* Get the size of the static and alignment requirements for the TLS
      block.  */
diff --git a/nptl/pthread_sigmask.c b/nptl/pthread_sigmask.c
index d266d296c5..7b65ae1f27 100644
--- a/nptl/pthread_sigmask.c
+++ b/nptl/pthread_sigmask.c
@@ -39,7 +39,7 @@ __pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
 
   /* We know that realtime signals are available if NPTL is used.  */
   int result = INTERNAL_SYSCALL_CALL (rt_sigprocmask, how, newmask,
-				      oldmask, _NSIG / 8);
+				      oldmask, __NSIG_BYTES);
 
   return (INTERNAL_SYSCALL_ERROR_P (result)
 	  ? INTERNAL_SYSCALL_ERRNO (result)
diff --git a/sysdeps/unix/sysv/linux/aio_misc.h b/sysdeps/unix/sysv/linux/aio_misc.h
index 30c3cd778e..e31ca8edbe 100644
--- a/sysdeps/unix/sysv/linux/aio_misc.h
+++ b/sysdeps/unix/sysv/linux/aio_misc.h
@@ -31,7 +31,8 @@ __aio_start_notify_thread (void)
 {
   sigset_t ss;
   sigemptyset (&ss);
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, NULL, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, NULL,
+			 __NSIG_BYTES);
 }
 
 extern inline int
@@ -52,12 +53,14 @@ __aio_create_helper_thread (pthread_t *threadp, void *(*tf) (void *),
   sigset_t ss;
   sigset_t oss;
   sigfillset (&ss);
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, &oss, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &ss, &oss,
+			 __NSIG_BYTES);
 
   int ret = pthread_create (threadp, &attr, tf, arg);
 
   /* Restore the signal mask.  */
-  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &oss, NULL, _NSIG / 8);
+  INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, &oss, NULL,
+			 __NSIG_BYTES);
 
   (void) pthread_attr_destroy (&attr);
   return ret;
diff --git a/sysdeps/unix/sysv/linux/epoll_pwait.c b/sysdeps/unix/sysv/linux/epoll_pwait.c
index 66f04482c7..af6d0fd713 100644
--- a/sysdeps/unix/sysv/linux/epoll_pwait.c
+++ b/sysdeps/unix/sysv/linux/epoll_pwait.c
@@ -38,6 +38,6 @@ int epoll_pwait (int epfd, struct epoll_event *events,
 		 const sigset_t *set)
 {
   return SYSCALL_CANCEL (epoll_pwait, epfd, events, maxevents,
-			 timeout, set, _NSIG / 8);
+			 timeout, set, __NSIG_BYTES);
 }
 libc_hidden_def (epoll_pwait)
diff --git a/sysdeps/unix/sysv/linux/internal-signals.h b/sysdeps/unix/sysv/linux/internal-signals.h
index 3fbd4807d1..35f2de04c5 100644
--- a/sysdeps/unix/sysv/linux/internal-signals.h
+++ b/sysdeps/unix/sysv/linux/internal-signals.h
@@ -68,7 +68,7 @@ static inline void
 __libc_signal_block_all (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigall_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Block all application signals (excluding internal glibc ones).  */
@@ -78,7 +78,7 @@ __libc_signal_block_app (sigset_t *set)
   sigset_t allset = sigall_set;
   __clear_internal_signals (&allset);
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &allset, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Block only SIGTIMER and return the previous set on SET.  */
@@ -86,7 +86,7 @@ static inline void
 __libc_signal_block_sigtimer (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_BLOCK, &sigtimer_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Unblock only SIGTIMER and return the previous set on SET.  */
@@ -94,7 +94,7 @@ static inline void
 __libc_signal_unblock_sigtimer (sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_UNBLOCK, &sigtimer_set, set,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Restore current process signal mask.  */
@@ -102,7 +102,7 @@ static inline void
 __libc_signal_restore_set (const sigset_t *set)
 {
   INTERNAL_SYSCALL_CALL (rt_sigprocmask, SIG_SETMASK, set, NULL,
-			 _NSIG / 8);
+			 __NSIG_BYTES);
 }
 
 /* Used to communicate with signal handler.  */
diff --git a/sysdeps/unix/sysv/linux/ppoll.c b/sysdeps/unix/sysv/linux/ppoll.c
index 4ffb23710e..0f15636cce 100644
--- a/sysdeps/unix/sysv/linux/ppoll.c
+++ b/sysdeps/unix/sysv/linux/ppoll.c
@@ -41,11 +41,12 @@ __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout,
 # ifndef __NR_ppoll_time64
 #  define __NR_ppoll_time64 __NR_ppoll
 # endif
-  return SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask, _NSIG / 8);
+  return SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask,
+			 __NSIG_BYTES);
 #else
 # ifdef __NR_ppoll_time64
   int ret = SYSCALL_CANCEL (ppoll_time64, fds, nfds, timeout, sigmask,
-                            _NSIG / 8);
+                            __NSIG_BYTES);
   if (ret >= 0 || errno != ENOSYS)
     return ret;
 # endif
@@ -62,7 +63,7 @@ __ppoll64 (struct pollfd *fds, nfds_t nfds, const struct __timespec64 *timeout,
     }
 
   return SYSCALL_CANCEL (ppoll, fds, nfds, timeout ? &ts32 : NULL, sigmask,
-                         _NSIG / 8);
+                         __NSIG_BYTES);
 #endif
 }
 
diff --git a/sysdeps/unix/sysv/linux/pselect.c b/sysdeps/unix/sysv/linux/pselect.c
index d7c6ff8fdb..304db03338 100644
--- a/sysdeps/unix/sysv/linux/pselect.c
+++ b/sysdeps/unix/sysv/linux/pselect.c
@@ -43,7 +43,7 @@ __pselect (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
   } data;
 
   data.ss = (__syscall_ulong_t) (uintptr_t) sigmask;
-  data.ss_len = _NSIG / 8;
+  data.ss_len = __NSIG_BYTES;
 
   return SYSCALL_CANCEL (pselect6, nfds, readfds, writefds, exceptfds,
                          timeout, &data);
diff --git a/sysdeps/unix/sysv/linux/sigaction.c b/sysdeps/unix/sysv/linux/sigaction.c
index 4e6d11a6ae..f27349d552 100644
--- a/sysdeps/unix/sysv/linux/sigaction.c
+++ b/sysdeps/unix/sysv/linux/sigaction.c
@@ -57,7 +57,8 @@ __libc_sigaction (int sig, const struct sigaction *act, struct sigaction *oact)
      real size of the user-level sigset_t.  */
   result = INLINE_SYSCALL_CALL (rt_sigaction, sig,
 				act ? &kact : NULL,
-				oact ? &koact : NULL, STUB (act, _NSIG / 8));
+				oact ? &koact : NULL, STUB (act,
+							    __NSIG_BYTES));
 
   if (oact && result >= 0)
     {
diff --git a/sysdeps/unix/sysv/linux/signalfd.c b/sysdeps/unix/sysv/linux/signalfd.c
index 64d7bccba9..71d91fdde5 100644
--- a/sysdeps/unix/sysv/linux/signalfd.c
+++ b/sysdeps/unix/sysv/linux/signalfd.c
@@ -24,5 +24,5 @@
 int
 signalfd (int fd, const sigset_t *mask, int flags)
 {
-  return INLINE_SYSCALL (signalfd4, 4, fd, mask, _NSIG / 8, flags);
+  return INLINE_SYSCALL (signalfd4, 4, fd, mask, __NSIG_BYTES, flags);
 }
diff --git a/sysdeps/unix/sysv/linux/sigpending.c b/sysdeps/unix/sysv/linux/sigpending.c
index 458a3cf99e..8898fe8b34 100644
--- a/sysdeps/unix/sysv/linux/sigpending.c
+++ b/sysdeps/unix/sysv/linux/sigpending.c
@@ -24,5 +24,5 @@
 int
 sigpending (sigset_t *set)
 {
-  return INLINE_SYSCALL (rt_sigpending, 2, set, _NSIG / 8);
+  return INLINE_SYSCALL_CALL (rt_sigpending, set, __NSIG_BYTES);
 }
diff --git a/sysdeps/unix/sysv/linux/sigsetops.h b/sysdeps/unix/sysv/linux/sigsetops.h
index db8f378cf0..3f29ead009 100644
--- a/sysdeps/unix/sysv/linux/sigsetops.h
+++ b/sysdeps/unix/sysv/linux/sigsetops.h
@@ -20,23 +20,31 @@
 #define _SIGSETOPS_H 1
 
 #include <signal.h>
+#include <limits.h>
+#include <libc-pointer-arith.h>
 
 /* Return a mask that includes the bit for SIG only.  */
-# define __sigmask(sig) \
-  (((unsigned long int) 1) << (((sig) - 1) % (8 * sizeof (unsigned long int))))
+#define __sigmask(sig) \
+  (1UL << (((sig) - 1) % ULONG_WIDTH))
 
 /* Return the word index for SIG.  */
 static inline unsigned long int
 __sigword (int sig)
 {
-  return (sig - 1) / (8 * sizeof (unsigned long int));
+  return (sig - 1) / ULONG_WIDTH;
 }
 
 /* Linux sig* functions only handle up to __NSIG_WORDS words instead of
    full _SIGSET_NWORDS sigset size.  The signal numbers are 1-based, and
    bit 0 of a signal mask is for signal 1.  */
-
-# define __NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int )))
+#define __NSIG_WORDS (ALIGN_UP ((_NSIG - 1), ULONG_WIDTH) / ULONG_WIDTH)
+_Static_assert (__NSIG_WORDS <= _SIGSET_NWORDS,
+		"__NSIG_WORDS > _SIGSET_WORDS");
+
+/* This macro is used on syscall that takes a sigset_t to specify the expected
+   size in bytes.  As for glibc, kernel sigset is implemented as an array of
+   unsigned long.  */
+#define __NSIG_BYTES (__NSIG_WORDS * (ULONG_WIDTH / UCHAR_WIDTH))
 
 static inline void
 __sigemptyset (sigset_t *set)
diff --git a/sysdeps/unix/sysv/linux/sigsuspend.c b/sysdeps/unix/sysv/linux/sigsuspend.c
index dd5df5af25..b4bf2ec4bc 100644
--- a/sysdeps/unix/sysv/linux/sigsuspend.c
+++ b/sysdeps/unix/sysv/linux/sigsuspend.c
@@ -23,7 +23,7 @@
 int
 __sigsuspend (const sigset_t *set)
 {
-  return SYSCALL_CANCEL (rt_sigsuspend, set, _NSIG / 8);
+  return SYSCALL_CANCEL (rt_sigsuspend, set, __NSIG_BYTES);
 }
 libc_hidden_def (__sigsuspend)
 weak_alias (__sigsuspend, sigsuspend)
diff --git a/sysdeps/unix/sysv/linux/sigtimedwait.c b/sysdeps/unix/sysv/linux/sigtimedwait.c
index 6b3d8f705f..f2ef3aad45 100644
--- a/sysdeps/unix/sysv/linux/sigtimedwait.c
+++ b/sysdeps/unix/sysv/linux/sigtimedwait.c
@@ -26,7 +26,8 @@ __sigtimedwait (const sigset_t *set, siginfo_t *info,
 {
   /* XXX The size argument hopefully will have to be changed to the
      real size of the user-level sigset_t.  */
-  int result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, timeout, _NSIG / 8);
+  int result = SYSCALL_CANCEL (rt_sigtimedwait, set, info, timeout,
+			       __NSIG_BYTES);
 
   /* The kernel generates a SI_TKILL code in si_code in case tkill is
      used.  tkill is transparently used in raise().  Since having
diff --git a/sysdeps/unix/sysv/linux/x86/setjmpP.h b/sysdeps/unix/sysv/linux/x86/setjmpP.h
index 1783b8eb78..a5de31bfd6 100644
--- a/sysdeps/unix/sysv/linux/x86/setjmpP.h
+++ b/sysdeps/unix/sysv/linux/x86/setjmpP.h
@@ -21,6 +21,7 @@
 
 #include <bits/types/__sigset_t.h>
 #include <libc-pointer-arith.h>
+#include <sigsetops.h>
 
 /* <setjmp/setjmp.h> has
 
@@ -113,11 +114,9 @@ typedef union
 
 #include <signal.h>
 
-#define _SIGPROCMASK_NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int)))
-
 typedef struct
   {
-    unsigned long int __val[_SIGPROCMASK_NSIG_WORDS];
+    unsigned long int __val[__NSIG_WORDS];
   } __sigprocmask_sigset_t;
 
 extern jmp_buf ___buf;