This is the mail archive of the glibc-bugs@sourceware.org mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[Bug libc/1951] New: sigset() does not correctly return SIG_HOLD


The logic of sigset() (sysdeps/posix/sigset.c) is tangled: when a signal
is blocked, it does not correctly return the previous disposition of the
signal in cases where the signal is currently blocked, or where the
disposition is being set to SIG_HOLD.

SUSv3 says the following:

    Upon successful completion, sigset() shall return SIG_HOLD if the
    signal had been blocked and the signal's previous disposition if
    it had not been blocked. Otherwise, SIG_ERR shall be returned and
    errno set to indicate the error.

In other words:

-- if the signal is currently blocked, then the return value of
   of a successful sigset() should always be SIG_HOLD, regardless
   of whether or not SIG_HOLD was specified as the new disposition.
   "TEST 1" below shows that glibc sigset() does not do this.

-- A successful sigset() call that specifies the new disposition
   as SIG_HOLD should return the previous disposition of the
   signal.  Instead (see "TEST 2" below), glibc sigset() always
   returns SIG_HOLD in this case.

I have included a test program at the foot of this mail.

When run on Linux/x86 glibc 2.3.5 (SUSE 10.0), we see the following:

    Linux tekapo 2.6.15-rc1-mm2 #6 SMP PREEMPT Wed Nov 23
    12:50:50 CET 2005 i686 i686 i386 GNU/Linux
    Wed Nov 30 13:38:12 CET 2005
    ===== TEST 1 =====
    Blocking signal with sighold()
    Signal mask after sighold()
                    2 (Interrupt)
    About to use sigset() to establish handler
    Previous disposition: SIG_DFL (should be SIG_HOLD)
    TEST FAILED!!!

    ===== TEST 2 =====
    About to use sigset() to set SIG_HOLD
    Previous disposition: SIG_HOLD (should be SIG_DFL)
    TEST FAILED!!!

    ===== TEST 3 =====
    About to use sigset() to set SIG_HOLD
    About to use sigset() to set SIG_HOLD (again)
    Previous disposition: SIG_HOLD (should be SIG_HOLD)

By contrast, here are the results on Solaris 8:

    SunOS sunbox 5.8 Generic_108528-27 sun4u sparc SUNW,Ultra-4
    Wed Nov 30 13:41:34 MET 2005
    ===== TEST 1 =====
    Blocking signal with sighold()
    Signal mask after sighold()
                    2 (Interrupt)
    About to use sigset() to establish handler
    Previous disposition: SIG_HOLD (should be SIG_HOLD)

    ===== TEST 2 =====
    About to use sigset() to set SIG_HOLD
    Previous disposition: SIG_DFL (should be SIG_DFL)

    ===== TEST 3 =====
    About to use sigset() to set SIG_HOLD
    About to use sigset() to set SIG_HOLD (again)
    Previous disposition: SIG_HOLD (should be SIG_HOLD)

And on HP-UX 11:

    HP-UX td192 B.11.11 U 9000/800 1839940656 unlimited-user license
    Wed Nov 30 07:42:00 EST 2005
    ===== TEST 1 =====
    Blocking signal with sighold()
    Signal mask after sighold()
                    2 (SIG-2)
    About to use sigset() to establish handler
    Previous disposition: SIG_HOLD (should be SIG_HOLD)

    ===== TEST 2 =====
    About to use sigset() to set SIG_HOLD
    Previous disposition: SIG_DFL (should be SIG_DFL)

    ===== TEST 3 =====
    About to use sigset() to set SIG_HOLD
    About to use sigset() to set SIG_HOLD (again)
    Previous disposition: SIG_HOLD (should be SIG_HOLD)

Cheers,

Michael

==========================

/* sigset_SIG_HOLD_bug.c */

#ifdef __sun
#define __EXTENSIONS__  /* To get NSIG defn */
#endif
#define _GNU_SOURCE
#define _XOPEN_SOURCE 500
#include <signal.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>

#define TEST_SIG SIGINT

typedef void (*sighandler_t)(int);

#define errExit(msg)            do { perror(msg); exit(EXIT_FAILURE); \
                                } while (0)

#ifdef __hpux

/* A very minimal implementation of strsignal()... */

#define BUF_SIZE 100

char *
strsignal(int sig)
{
    static char buf[BUF_SIZE];

    snprintf(buf, BUF_SIZE, "SIG-%d", sig);
    return buf;
} /* strsignal */

#endif

static void     /* Print mask of blocked signals for this process */
printSigMask(const char *msg)
{
    sigset_t currMask;
    int sig, cnt;

    if (msg != NULL)
        printf("%s", msg);

    if (sigprocmask(SIG_BLOCK, NULL, &currMask) == -1)
        errExit("sigaction");

    cnt = 0;
    for (sig = 1; sig < NSIG; sig++) {
        if (sigismember(&currMask, sig)) {
            cnt++;
            printf("\t\t%d (%s)\n", sig, strsignal(sig));
        }
    }

    if (cnt == 0)
        printf("\t\t<empty signal set>\n");
} /* printSigMask */

static void
handler(int sig)
{
    printf("Caught signal %d\n", sig);
    printSigMask("Signal mask in handler\n");
    sleep(3);
    printf("Handler returning\n");
} /* handler */

static void
printDisposition(sighandler_t disp)
{
    if (disp == SIG_HOLD)
        printf("SIG_HOLD");
    else if (disp == SIG_DFL)
        printf("SIG_DFL");
    else if (disp == SIG_IGN)
        printf("SIG_IGN");
    else
        printf("handled at %lx", (long) disp);
} /* printDisposition */

static void
returnTest1(void)
{
    sighandler_t prev;

    printf("===== TEST 1 =====\n");
    printf("Blocking signal with sighold()\n");
    if (sighold(TEST_SIG) == -1)errExit("sighold");
    printSigMask("Signal mask after sighold()\n");

    printf("About to use sigset() to establish handler\n");
    prev = sigset(TEST_SIG, handler);
    if (prev == SIG_ERR) errExit("sigset");

    printf("Previous disposition: ");
    printDisposition(prev);
    printf(" (should be SIG_HOLD)\n");
    if (prev != SIG_HOLD)
        printf("TEST FAILED!!!\n");
} /* returnTest1 */

static void
returnTest2(void)
{
    sighandler_t prev;

    printf("\n===== TEST 2 =====\n");

    printf("About to use sigset() to set SIG_HOLD\n");
    prev = sigset(TEST_SIG, SIG_HOLD);
    if (prev == SIG_ERR) errExit("sigset");

    printf("Previous disposition: ");
    printDisposition(prev);
    printf(" (should be SIG_DFL)\n");
    if (prev != SIG_DFL)
        printf("TEST FAILED!!!\n");
} /* returnTest2 */

static void
returnTest3(void)
{
    sighandler_t prev;

    printf("\n===== TEST 3 =====\n");

    printf("About to use sigset() to set SIG_HOLD\n");
    prev = sigset(TEST_SIG, SIG_HOLD);
    if (prev == SIG_ERR) errExit("sigset");

    printf("About to use sigset() to set SIG_HOLD (again)\n");
    prev = sigset(TEST_SIG, SIG_HOLD);
    if (prev == SIG_ERR) errExit("sigset");

    printf("Previous disposition: ");
    printDisposition(prev);
    printf(" (should be SIG_HOLD)\n");
    if (prev != SIG_HOLD)
        printf("TEST FAILED!!!\n");
} /* returnTest3 */

int
main(int argc, char *argv[])
{
    pid_t childPid;

    system("uname -a; date\n");
    childPid = fork();
    if (childPid == -1) errExit("fork");

    if (childPid == 0) {
        returnTest1();
        exit(EXIT_SUCCESS);
    } else
        wait(NULL);

    childPid = fork();
    if (childPid == -1) errExit("fork");

    if (childPid == 0) {
        returnTest2();
        exit(EXIT_SUCCESS);
    } else
        wait(NULL);

    childPid = fork();
    if (childPid == -1) errExit("fork");

    if (childPid == 0) {
        returnTest3();
        exit(EXIT_SUCCESS);
    } else
        wait(NULL);

    exit(EXIT_SUCCESS);
} /* main */

-- 
           Summary: sigset() does not correctly return SIG_HOLD
           Product: glibc
           Version: 2.3.5
            Status: NEW
          Severity: normal
          Priority: P2
         Component: libc
        AssignedTo: drepper at redhat dot com
        ReportedBy: michael dot kerrisk at gmx dot net
                CC: glibc-bugs at sources dot redhat dot com


http://sourceware.org/bugzilla/show_bug.cgi?id=1951

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]