This is the mail archive of the
glibc-bugs@sourceware.org
mailing list for the glibc project.
[Bug libc/1951] New: sigset() does not correctly return SIG_HOLD
- From: "michael dot kerrisk at gmx dot net" <sourceware-bugzilla at sourceware dot org>
- To: glibc-bugs at sources dot redhat dot com
- Date: 30 Nov 2005 12:52:18 -0000
- Subject: [Bug libc/1951] New: sigset() does not correctly return SIG_HOLD
- Reply-to: sourceware-bugzilla at sourceware dot org
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.