x86 fork/sigaction issue

Jon Turney jon.turney@dronecode.org.uk
Tue Sep 6 15:56:00 GMT 2016


Attached is a test case, extracted from pixman's fence-image-self-test 
testcase.

This seems work fine on x86_64, but fails on x86.   This seems to be a 
regression, as it works correctly with Cygwin 2.3.1, but fails with 
2.4.1 and later.

Poking at this with gdb, it seems that the child exits with a status 
indicating that it was terminated by SIGSEGV, so it's almost as if the 
signal handler somehow doesn't get installed properly.

This also seems to work correctly when straced, so I'm not sure what to 
make of that or how to investigate further...
-------------- next part --------------
#include <errno.h>
#include <signal.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <unistd.h>

static void
segv_handler (int sig, siginfo_t *si, void *unused)
{
    _exit (EXIT_SUCCESS);
}

static void
die (const char *msg, int err)
{
    if (err)
        perror (msg);
    else
        fprintf (stderr, "%s\n", msg);

    abort ();
}

static void
do_expect_signal (void (*fn)(void))
{
    struct sigaction sa;

    sa.sa_flags = SA_SIGINFO;
    sigemptyset (&sa.sa_mask);
    sa.sa_sigaction = segv_handler;
    if (sigaction (SIGSEGV, &sa, NULL) == -1)
        die ("sigaction failed", errno);

    (*fn)();

    _exit (EXIT_FAILURE);
}

static bool
expect_signal (void (*fn)(void))
{
    pid_t pid, wp;
    int status;

    pid = fork ();
    if (pid == -1)
        die ("fork failed", errno);

    if (pid == 0)
        do_expect_signal (fn); /* never returns */

    wp = waitpid (pid, &status, 0);
    if (wp != pid)
        die ("waitpid did not work", wp == -1 ? errno : 0);

    if (WIFEXITED (status) && WEXITSTATUS (status) == EXIT_SUCCESS)
        return true;

    return false;
}

static void
deref (void)
{
  *((char *)0) = 0;
}

static bool
fault (void)
{
  if (expect_signal(deref))
    {
      printf("Signal OK\n");
      return true;
    }
  return false;
}

int
main (int argc, char **argv)
{
  bool ok = true;
  ok = fault();
  if (ok)
    return EXIT_SUCCESS;
  return EXIT_FAILURE;
}


More information about the Cygwin-developers mailing list