Segfault in pthread_sigqueue() or sigtimewait()

Christian Franke Christian.Franke@t-online.de
Thu Nov 14 12:55:36 GMT 2024


After enabling the usage of pthread_sigqueue() in stress-ng, 'stress-ng 
--pthread ...' occasionally reports that child processes failed with 
SIGSEGV.

The problem is unrelated to the recent fix of the signature of 
pthread_sigqueue():
https://cygwin.com/git/?p=newlib-cygwin.git;a=commit;h=1e8c92e

It could be reproduced with Cygwin 3.5.4-1 and with current 3.6.0 TEST 
release if the signature is adjusted.

Testcase (attached):

$ gcc -O2 -o sigfault sigfault.c # Add -DBETA if compiling for a TEST 
release

$ strace -o trace.log ./sigfault
pthread_create({0xa000188d0}, ...)=0
pthread_sigqueue(0xa000188d0, SIGUSR1, .)
sigtimedwait(...)=30 (errno=0)
...
sigtimedwait(...)=30 (errno=0)
pthread_sigqueue(0xa000188d0, SIGUSR1, .)=0
pthread_join(0xa000188d0, .)=0
pthread_create({0xa000188d0}, ...)=0
pthread_sigqueue(0xa000188d0, SIGUSR1, .)
sigtimedwait(...)=30 (errno=0)
pthread_sigqueue(0xa000188d0, SIGUSR1, .)=0
pthread_join(0xa000188d0, .)=0
pthread_create({0xa000188d0}, ...)=0
pthread_sigqueue(0xa000188d0, SIGUSR1, .)
Segmentation fault

$ cat trace.log
...
    78  103937 [main] sigfault 2074 sig_send: Waiting for pack.wakeup 0x21C
    80  104017 [sig] sigfault 2074 sigpacket::process: signal 30 processing
   147  104164 [sigfault] sigfault 2074 __set_errno: int 
sigwait_common(const sigset_t*, siginfo_t*, PLARGE_INTEGER):643 setting 
errno 11
   103  104267 [sig] sigfault 2074 sigpacket::process: signal 30, signal 
handler 0x1
    84  104351 [sigfault] sigfault 2074 sigwait_common: returning signal -1
    81  104432 [sig] sigfault 2074 sigpacket::setup_handler: controlled 
interrupt. stackptr 0x7FFDFE220, stack 0x7FFDFE218, stackptr[-1] 0x100401109
    78  104510 [sig] sigfault 2074 proc_subproc: args: 4, 1
    74  104584 [sig] sigfault 2074 proc_subproc: clear waiting threads
    71  104655 [sig] sigfault 2074 proc_subproc: finished clearing
    70  104725 [sig] sigfault 2074 proc_subproc: returning 1
   125  104850 [sig] sigfault 2074 _cygtls::interrupt_setup: armed 
signal_arrived 0x24C, signal 30
    74  104924 [sig] sigfault 2074 sigpacket::setup_handler: signal 30 
delivered
    83  105007 [sigfault] sigfault 2074 set_process_mask_delta: oldmask 
0, newmask 20000000, deltamask 20000000
--- Process 9568 (pid: 2074), exception c0000005 at 0000000000000001
    80  105087 [sig] sigfault 2074 sigpacket::process: returning 1
--- Process 9568 (pid: 2074) thread 7320 exited with status 0xc0000005
--- Process 9568 (pid: 2074) thread 8928 exited with status 0xc0000005
--- Process 9568 (pid: 2074) thread 6792 exited with status 0xc0000005
--- Process 9568 (pid: 2074) thread 5020 exited with status 0xc0000005
--- Process 9568 thread 9020 exited with status 0xc0000005
--- Process 9568 exited with status 0xc0000005

I guess the problem occurs because pthread_sigqueue() is sometimes 
issued after the thread function already returned. The thread pointer 
should be valid until pthread_join() is called. Sorry if I missed something.

-- 
Regards,
Christian

-------------- next part --------------
#define _GNU_SOURCE
#include <errno.h>
#include <pthread.h>
#include <stdio.h>

static volatile char started, stop;

static void * threadfunc(void *arg)
{
  (void)arg;

  started = 1;
  while (!stop)
    sched_yield();

  siginfo_t info = {0};
  sigset_t mask; sigemptyset(&mask);
  sigaddset(&mask, SIGUSR1);
  struct timespec timeout;
  timeout.tv_sec = 0; timeout.tv_nsec = 1000;

  errno = 0;
  int ret = sigtimedwait(&mask, &info, &timeout);
  printf("sigtimedwait(...)=%d (errno=%d)\n", ret, errno); fflush(stdout);

  return NULL;
}

int main()
{
  signal(SIGUSR1, SIG_IGN);

  for (int i = 0; i < 1000; i++) {
    started = stop = 0;

    pthread_t t = NULL;
    int ret = pthread_create(&t, NULL, threadfunc, NULL);
    printf("pthread_create({%p}, ...)=%d\n", t, ret); fflush(stdout);
    if (ret)
      return 1;

    while (!started)
      sched_yield();
    stop = 1;

    union sigval value = {0};
    printf("pthread_sigqueue(%p, SIGUSR1, .)\n", t); fflush(stdout);
#ifdef BETA
    ret = pthread_sigqueue(t, SIGUSR1, value);
#else
    ret = pthread_sigqueue(&t, SIGUSR1, value);
#endif
    printf("pthread_sigqueue(%p, SIGUSR1, .)=%d\n", t, ret); fflush(stdout);
    if (ret)
      return 1;

    ret = pthread_join(t, NULL);
    printf("pthread_join(%p, .)=%d\n", t, ret); fflush(stdout);
    if (ret)
      return 1;
  }

  printf("done\n");
  return 0;
}


More information about the Cygwin mailing list