Skip to content

Commit

Permalink
nptl: pthread_kill needs to return ESRCH for old programs (bug 19193)
Browse files Browse the repository at this point in the history
The fix for bug 19193 breaks some old applications which appear
to use pthread_kill to probe if a thread is still running, something
that is not supported by POSIX.

(cherry picked from commit 95dba35)
  • Loading branch information
fweimer-rh committed Sep 20, 2021
1 parent 433ec4f commit 73c7f5a
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 10 deletions.
37 changes: 29 additions & 8 deletions nptl/pthread_kill.c
Expand Up @@ -21,8 +21,11 @@
#include <pthreadP.h>
#include <shlib-compat.h>

int
__pthread_kill_internal (pthread_t threadid, int signo)
/* Sends SIGNO to THREADID. If the thread is about to exit or has
already exited on the kernel side, return NO_TID. Otherwise return
0 or an error code. */
static int
__pthread_kill_implementation (pthread_t threadid, int signo, int no_tid)
{
struct pthread *pd = (struct pthread *) threadid;
if (pd == THREAD_SELF)
Expand Down Expand Up @@ -52,11 +55,8 @@ __pthread_kill_internal (pthread_t threadid, int signo)
signal is either not observable (the target thread has already
blocked signals at this point), or it will fail, or it might be
delivered to a new, unrelated thread that has reused the TID.
So do not actually send the signal. Do not report an error
because the threadid argument is still valid (the thread ID
lifetime has not ended), and ESRCH (for example) would be
misleading. */
ret = 0;
So do not actually send the signal. */
ret = no_tid;
else
{
/* Using tgkill is a safety measure. pd->exit_lock ensures that
Expand All @@ -71,6 +71,15 @@ __pthread_kill_internal (pthread_t threadid, int signo)
return ret;
}

int
__pthread_kill_internal (pthread_t threadid, int signo)
{
/* Do not report an error in the no-tid case because the threadid
argument is still valid (the thread ID lifetime has not ended),
and ESRCH (for example) would be misleading. */
return __pthread_kill_implementation (threadid, signo, 0);
}

int
__pthread_kill (pthread_t threadid, int signo)
{
Expand All @@ -81,13 +90,25 @@ __pthread_kill (pthread_t threadid, int signo)

return __pthread_kill_internal (threadid, signo);
}

/* Some architectures (for instance arm) might pull raise through libgcc, so
avoid the symbol version if it ends up being used on ld.so. */
#if !IS_IN(rtld)
libc_hidden_def (__pthread_kill)
versioned_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_34);

# if OTHER_SHLIB_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34)
compat_symbol (libc, __pthread_kill, pthread_kill, GLIBC_2_0);
/* Variant which returns ESRCH in the no-TID case, for backwards
compatibility. */
int
attribute_compat_text_section
__pthread_kill_esrch (pthread_t threadid, int signo)
{
if (__is_internal_signal (signo))
return EINVAL;

return __pthread_kill_implementation (threadid, signo, ESRCH);
}
compat_symbol (libc, __pthread_kill_esrch, pthread_kill, GLIBC_2_0);
# endif
#endif
21 changes: 19 additions & 2 deletions sysdeps/pthread/tst-pthread_kill-exited.c
Expand Up @@ -16,11 +16,15 @@
License along with the GNU C Library; if not, see
<https://www.gnu.org/licenses/>. */

/* This test verifies that pthread_kill returns 0 (and not ESRCH) for
a thread that has exited on the kernel side. */
/* This test verifies that the default pthread_kill returns 0 (and not
ESRCH) for a thread that has exited on the kernel side. */

#include <errno.h>
#include <pthread.h>
#include <shlib-compat.h>
#include <signal.h>
#include <stddef.h>
#include <support/check.h>
#include <support/support.h>
#include <support/xthread.h>

Expand All @@ -30,14 +34,27 @@ noop_thread (void *closure)
return NULL;
}

#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
extern __typeof (pthread_kill) compat_pthread_kill;
compat_symbol_reference (libpthread, compat_pthread_kill, pthread_kill,
GLIBC_2_0);
#endif

static int
do_test (void)
{
pthread_t thr = xpthread_create (NULL, noop_thread, NULL);

support_wait_for_thread_exit ();

/* NB: Always uses the default symbol due to separate compilation. */
xpthread_kill (thr, SIGUSR1);

#if TEST_COMPAT (libpthread, GLIBC_2_0, GLIBC_2_34) && PTHREAD_IN_LIBC
/* Old binaries need the non-conforming ESRCH error code. */
TEST_COMPARE (compat_pthread_kill (thr, SIGUSR1), ESRCH);
#endif

xpthread_join (thr);

return 0;
Expand Down

0 comments on commit 73c7f5a

Please sign in to comment.