[PATCH 4/4] signal: Only handle on NSIG signals on signal functions (BZ #25657)

Adhemerval Zanella adhemerval.zanella@linaro.org
Fri Apr 17 13:25:26 GMT 2020


Ping.

On 13/03/2020 16:48, Adhemerval Zanella wrote:
> The upper bits of the sigset_t s not fully initialized in the signal
> mask calls that return information from kernel (sigprocmask,
> sigpending, and pthread_sigmask), since the exported sigset_t size
> (1024 bits) is larger than Linux support one (64 or 128 bits).
> It might make sigisemptyset/sigorset/sigandset fail if the mask
> is filled prior the call.
> 
> This patch changes the internal signal function to handle up to
> supported Linux signal number (_NSIG), the remaining bits are
> untouched.
> 
> Checked on x86_64-linux-gnu and i686-linux-gnu.
> ---
>  nptl/Makefile                        |   2 +-
>  nptl/pthread_sigmask.c               |   7 +-
>  nptl/tst-signal8.c                   |  62 ++++++++++++
>  signal/Makefile                      |   1 +
>  signal/sigsetops.c                   |  12 +--
>  signal/tst-sigisemptyset.c           |  95 ++++++++++++++++++
>  sysdeps/unix/sysv/linux/sigpending.c |   6 +-
>  sysdeps/unix/sysv/linux/sigsetops.h  | 143 +++++++++++++--------------
>  8 files changed, 236 insertions(+), 92 deletions(-)
>  create mode 100644 nptl/tst-signal8.c
>  create mode 100644 signal/tst-sigisemptyset.c
> 
> diff --git a/nptl/Makefile b/nptl/Makefile
> index 4816fa254e..33fa03807e 100644
> --- a/nptl/Makefile
> +++ b/nptl/Makefile
> @@ -293,7 +293,7 @@ tests = tst-attr2 tst-attr3 tst-default-attr \
>  	tst-cleanup0 tst-cleanup1 tst-cleanup2 tst-cleanup3 tst-cleanup4 \
>  	tst-flock1 tst-flock2 \
>  	tst-signal1 tst-signal2 tst-signal3 tst-signal4 tst-signal5 \
> -	tst-signal6 \
> +	tst-signal6 tst-signal8 \
>  	tst-exec1 tst-exec2 tst-exec3 tst-exec4 tst-exec5 \
>  	tst-exit1 tst-exit2 tst-exit3 \
>  	tst-stdio1 tst-stdio2 \
> diff --git a/nptl/pthread_sigmask.c b/nptl/pthread_sigmask.c
> index c6c6e83c08..d266d296c5 100644
> --- a/nptl/pthread_sigmask.c
> +++ b/nptl/pthread_sigmask.c
> @@ -29,12 +29,11 @@ __pthread_sigmask (int how, const sigset_t *newmask, sigset_t *oldmask)
>    /* The only thing we have to make sure here is that SIGCANCEL and
>       SIGSETXID is not blocked.  */
>    if (newmask != NULL
> -      && (__builtin_expect (__sigismember (newmask, SIGCANCEL), 0)
> -	  || __builtin_expect (__sigismember (newmask, SIGSETXID), 0)))
> +      && (__glibc_unlikely (__sigismember (newmask, SIGCANCEL))
> +         || __glibc_unlikely (__sigismember (newmask, SIGSETXID))))
>      {
>        local_newmask = *newmask;
> -      __sigdelset (&local_newmask, SIGCANCEL);
> -      __sigdelset (&local_newmask, SIGSETXID);
> +      __clear_internal_signals (&local_newmask);
>        newmask = &local_newmask;
>      }
>  
> diff --git a/nptl/tst-signal8.c b/nptl/tst-signal8.c
> new file mode 100644
> index 0000000000..9da7e5ef07
> --- /dev/null
> +++ b/nptl/tst-signal8.c
> @@ -0,0 +1,62 @@
> +/* Tests for sigisemptyset and pthread_sigmask.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <signal.h>
> +
> +#include <support/check.h>
> +#include <support/xthread.h>
> +
> +static void *
> +tf (void *arg)
> +{
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (pthread_sigmask (SIG_BLOCK, 0, &set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigfillset (&set);
> +    TEST_COMPARE (pthread_sigmask (SIG_BLOCK, 0, &set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  return NULL;
> +}
> +
> +static int
> +do_test (void)
> +{
> +  /* Ensure current SIG_BLOCK mask empty.  */
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (sigprocmask (SIG_BLOCK, &set, 0), 0);
> +  }
> +
> +  {
> +    pthread_t thr = xpthread_create (NULL, tf, NULL);
> +    xpthread_join (thr);
> +  }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/signal/Makefile b/signal/Makefile
> index 37de438bba..f3c19e2992 100644
> --- a/signal/Makefile
> +++ b/signal/Makefile
> @@ -49,6 +49,7 @@ tests		:= tst-signal tst-sigset tst-sigsimple tst-raise tst-sigset2 \
>  		   tst-sigwait-eintr tst-sigaction \
>  		   tst-minsigstksz-1 tst-minsigstksz-2 tst-minsigstksz-3 \
>  		   tst-minsigstksz-3a tst-minsigstksz-4 \
> +		   tst-sigisemptyset
>  
>  include ../Rules
>  
> diff --git a/signal/sigsetops.c b/signal/sigsetops.c
> index eb89e6780e..1165377876 100644
> --- a/signal/sigsetops.c
> +++ b/signal/sigsetops.c
> @@ -26,28 +26,28 @@
>  
>  int
>  attribute_compat_text_section
> -(__sigismember) (const __sigset_t *set, int sig)
> +__sigismember_compat (const __sigset_t *set, int sig)
>  {
>    return __sigismember (set, sig);
>  }
> -compat_symbol (libc, __sigismember, __sigismember, GLIBC_2_0);
> +compat_symbol (libc, __sigismember_compat, __sigismember, GLIBC_2_0);
>  
>  int
>  attribute_compat_text_section
> -(__sigaddset) (__sigset_t *set, int sig)
> +__sigaddset_compat (__sigset_t *set, int sig)
>  {
>    __sigaddset (set, sig);
>    return 0;
>  }
> -compat_symbol (libc, __sigaddset, __sigaddset, GLIBC_2_0);
> +compat_symbol (libc, __sigaddset_compat, __sigaddset, GLIBC_2_0);
>  
>  int
>  attribute_compat_text_section
> -(__sigdelset) (__sigset_t *set, int sig)
> +__sigdelset_compat (__sigset_t *set, int sig)
>  {
>    __sigdelset (set, sig);
>    return 0;
>  }
> -compat_symbol (libc, __sigdelset, __sigdelset, GLIBC_2_0);
> +compat_symbol (libc, __sigdelset_compat, __sigdelset, GLIBC_2_0);
>  
>  #endif
> diff --git a/signal/tst-sigisemptyset.c b/signal/tst-sigisemptyset.c
> new file mode 100644
> index 0000000000..9ed95496f2
> --- /dev/null
> +++ b/signal/tst-sigisemptyset.c
> @@ -0,0 +1,95 @@
> +/* Tests for sigisemptyset/sigorset/sigandset.
> +   Copyright (C) 2020 Free Software Foundation, Inc.
> +   This file is part of the GNU C Library.
> +
> +   The GNU C Library is free software; you can redistribute it and/or
> +   modify it under the terms of the GNU Lesser General Public
> +   License as published by the Free Software Foundation; either
> +   version 2.1 of the License, or (at your option) any later version.
> +
> +   The GNU C Library is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
> +   Lesser General Public License for more details.
> +
> +   You should have received a copy of the GNU Lesser General Public
> +   License along with the GNU C Library; if not, see
> +   <https://www.gnu.org/licenses/>.  */
> +
> +#include <signal.h>
> +
> +#include <support/check.h>
> +
> +static int
> +do_test (void)
> +{
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigfillset (&set);
> +    TEST_COMPARE (sigisemptyset (&set), 0);
> +  }
> +
> +  {
> +    sigset_t setfill, setempty, set;
> +    sigfillset (&setfill);
> +    sigemptyset (&setempty);
> +
> +    sigorset (&set, &setfill, &setempty);
> +    TEST_COMPARE (sigisemptyset (&set), 0);
> +
> +    sigandset (&set, &setfill, &setempty);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  /* Ensure current SIG_BLOCK mask empty.  */
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (sigprocmask (SIG_BLOCK, &set, 0), 0);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (sigprocmask (SIG_BLOCK, 0, &set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigfillset (&set);
> +    TEST_COMPARE (sigprocmask (SIG_BLOCK, 0, &set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  /* Block all signals.  */
> +  {
> +    sigset_t set;
> +    sigfillset (&set);
> +    TEST_COMPARE (sigprocmask (SIG_BLOCK, &set, 0), 0);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigemptyset (&set);
> +    TEST_COMPARE (sigpending (&set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  {
> +    sigset_t set;
> +    sigfillset (&set);
> +    TEST_COMPARE (sigpending (&set), 0);
> +    TEST_COMPARE (sigisemptyset (&set), 1);
> +  }
> +
> +  return 0;
> +}
> +
> +#include <support/test-driver.c>
> diff --git a/sysdeps/unix/sysv/linux/sigpending.c b/sysdeps/unix/sysv/linux/sigpending.c
> index f6bedb5182..458a3cf99e 100644
> --- a/sysdeps/unix/sysv/linux/sigpending.c
> +++ b/sysdeps/unix/sysv/linux/sigpending.c
> @@ -15,13 +15,9 @@
>     License along with the GNU C Library; if not, see
>     <https://www.gnu.org/licenses/>.  */
>  
> -#include <errno.h>
>  #include <signal.h>
> -#include <unistd.h>
> -
>  #include <sysdep.h>
> -#include <sys/syscall.h>
> -
> +#include <sigsetops.h>
>  
>  /* Change the set of blocked signals to SET,
>     wait until a signal arrives, and restore the set of blocked signals.  */
> diff --git a/sysdeps/unix/sysv/linux/sigsetops.h b/sysdeps/unix/sysv/linux/sigsetops.h
> index cb97c98b10..f6ca34c842 100644
> --- a/sysdeps/unix/sysv/linux/sigsetops.h
> +++ b/sysdeps/unix/sysv/linux/sigsetops.h
> @@ -28,81 +28,72 @@
>  /* Return the word index for SIG.  */
>  # define __sigword(sig) (((sig) - 1) / (8 * sizeof (unsigned long int)))
>  
> -# define __sigemptyset(set)					\
> -  (__extension__ ({						\
> -    int __cnt = _SIGSET_NWORDS;					\
> -    sigset_t *__set = (set);					\
> -    while (--__cnt >= 0)					\
> -      __set->__val[__cnt] = 0;					\
> -    (void)0;							\
> -  }))
> -
> -# define __sigfillset(set)					\
> -  (__extension__ ({						\
> -    int __cnt = _SIGSET_NWORDS;					\
> -    sigset_t *__set = (set);					\
> -    while (--__cnt >= 0)					\
> -      __set->__val[__cnt] = ~0UL;				\
> -    (void)0;							\
> -  }))
> -
> -# define __sigisemptyset(set)					\
> -  (__extension__ ({						\
> -    int __cnt = _SIGSET_NWORDS;					\
> -    const sigset_t *__set = (set);				\
> -    int __ret = __set->__val[--__cnt];				\
> -    while (!__ret && --__cnt >= 0)				\
> -      __ret = __set->__val[__cnt];				\
> -    __ret == 0;							\
> -  }))
> -
> -# define __sigandset(dest, left, right)				\
> -  (__extension__ ({						\
> -    int __cnt = _SIGSET_NWORDS;					\
> -    sigset_t *__dest = (dest);					\
> -    const sigset_t *__left = (left);				\
> -    const sigset_t *__right = (right);				\
> -    while (--__cnt >= 0)					\
> -      __dest->__val[__cnt] = (__left->__val[__cnt]		\
> -			      & __right->__val[__cnt]);		\
> -    (void)0;							\
> -  }))
> -
> -# define __sigorset(dest, left, right)				\
> -  (__extension__ ({						\
> -    int __cnt = _SIGSET_NWORDS;					\
> -    sigset_t *__dest = (dest);					\
> -    const sigset_t *__left = (left);				\
> -    const sigset_t *__right = (right);				\
> -    while (--__cnt >= 0)					\
> -      __dest->__val[__cnt] = (__left->__val[__cnt]		\
> -			      | __right->__val[__cnt]);		\
> -    (void)0;							\
> -  }))
> -
> -/* These macros needn't check for a bogus signal number;
> -   error checking is done in the non-__ versions.  */
> -# define __sigismember(set, sig)				\
> -  (__extension__ ({						\
> -    unsigned long int __mask = __sigmask (sig);			\
> -    unsigned long int __word = __sigword (sig);			\
> -    (set)->__val[__word] & __mask ? 1 : 0;			\
> -  }))
> -
> -# define __sigaddset(set, sig)					\
> -  (__extension__ ({						\
> -    unsigned long int __mask = __sigmask (sig);			\
> -    unsigned long int __word = __sigword (sig);			\
> -    (set)->__val[__word] |= __mask;				\
> -    (void)0;							\
> -  }))
> -
> -# define __sigdelset(set, sig)					\
> -  (__extension__ ({						\
> -    unsigned long int __mask = __sigmask (sig);			\
> -    unsigned long int __word = __sigword (sig);			\
> -    (set)->__val[__word] &= ~__mask;				\
> -    (void)0;							\
> - }))
> +# define __NSIG_WORDS (_NSIG / (8 * sizeof (unsigned long int )))
> +
> +static inline void
> +__sigemptyset (sigset_t *set)
> +{
> +  int cnt = __NSIG_WORDS;
> +  while (--cnt >= 0)
> +   set->__val[cnt] = 0;
> +}
> +
> +static inline void
> +__sigfillset (sigset_t *set)
> +{
> +  int cnt = __NSIG_WORDS;
> +  while (--cnt >= 0)
> +   set->__val[cnt] = ~0UL;
> +}
> +
> +static inline int
> +__sigisemptyset (const sigset_t *set)
> +{
> +  int cnt = __NSIG_WORDS;
> +  int ret = set->__val[--cnt];
> +  while (ret == 0 && --cnt >= 0)
> +    ret = set->__val[cnt];
> +  return ret == 0;
> +}
> +
> +static inline void
> +__sigandset (sigset_t *dest, const sigset_t *left, const sigset_t *right)
> +{
> +  int cnt = __NSIG_WORDS;
> +  while (--cnt >= 0)
> +    dest->__val[cnt] = left->__val[cnt] & right->__val[cnt];
> +}
> +
> +static inline void
> +__sigorset (sigset_t *dest, const sigset_t *left, const sigset_t *right)
> +{
> +  int cnt = __NSIG_WORDS;
> +  while (--cnt >= 0)
> +    dest->__val[cnt] = left->__val[cnt] | right->__val[cnt];
> +}
> +
> +static inline int
> +__sigismember (const sigset_t *set, int sig)
> +{
> +  unsigned long int mask = __sigmask (sig);
> +  unsigned long int word = __sigword (sig);
> +  return set->__val[word] & mask ? 1 : 0;
> +}
> +
> +static inline void
> +__sigaddset (sigset_t *set, int sig)
> +{
> +  unsigned long int mask = __sigmask (sig);
> +  unsigned long int word = __sigword (sig);
> +  set->__val[word] |= mask;
> +}
> +
> +static inline void
> +__sigdelset (sigset_t *set, int sig)
> +{
> +  unsigned long int mask = __sigmask (sig);
> +  unsigned long int word = __sigword (sig);
> +  set->__val[word] &= ~mask;
> +}
>  
>  #endif /* bits/sigsetops.h */
> 


More information about the Libc-alpha mailing list