threads/154893: pthread_sigmask don't work if mask and oldmask are
passed the same pointer
KOSAKI Motohiro
kosaki.motohiro at gmail.com
Sat Feb 19 18:10:13 UTC 2011
>Number: 154893
>Category: threads
>Synopsis: pthread_sigmask don't work if mask and oldmask are passed the same pointer
>Confidential: no
>Severity: non-critical
>Priority: low
>Responsible: freebsd-threads
>State: open
>Quarter:
>Keywords:
>Date-Required:
>Class: sw-bug
>Submitter-Id: current-users
>Arrival-Date: Sat Feb 19 18:10:12 UTC 2011
>Closed-Date:
>Last-Modified:
>Originator: KOSAKI Motohiro
>Release: 8.1
>Organization:
>Environment:
FreeBSD FreeBSD8 8.1-RELEASE FreeBSD 8.1-RELEASE #0: Mon Jul 19 02:36:49 UTC 2010 root at mason.cse.buffalo.edu:/\
usr/obj/usr/src/sys/GENERIC amd64
>Description:
Programmers expect pthread_sigmask(SIG_SETMASK, &msk, &msk) mean
1) rewritten signal mask by msk.
2) and, return old signal mask to msk.
But, FreeBSD doesn't. Its pthread_sigmask behave the same as
pthread_sigmask(SIG_SETMASK, NULL, &msk). It is very strange to me.
Sidenote:
man sigprocmask says its type is below.
int
sigprocmask(int how, const sigset_t * restrict set,
sigset_t * restrict oset);
It is not POSIX compliant nor user friendly. But the man page
clealy describe set==oset is invalid.
At least, pthread_sigmask's man page shold be fixed if uthread maintainers
woun't fix this issue.
Sidenote2:
This is a source of signal breakage of ruby trunk.
http://redmine.ruby-lang.org/issues/show/4173
>How-To-Repeat:
run following program
------------------------------------------------------
#include <pthread.h>
#include <signal.h>
#include <stdio.h>
void* func(void* arg)
{
sigset_t old;
sigset_t add;
int i;
sigemptyset(&old);
pthread_sigmask(SIG_BLOCK, NULL, &old);
printf("before: ");
for (i=0; i<4; i++)
printf(" %08x", old.__bits[i]);
printf("\n");
sigemptyset(&add);
sigaddset(&add, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &add, NULL);
pthread_sigmask(SIG_BLOCK, NULL, &old);
printf("after: ");
for (i=0; i<4; i++)
printf(" %08x", old.__bits[i]);
printf("\n");
return 0;
}
void* func2(void* arg)
{
sigset_t old;
sigset_t add;
int i;
sigemptyset(&old);
pthread_sigmask(SIG_BLOCK, NULL, &old);
printf("before: ");
for (i=0; i<4; i++)
printf(" %08x", old.__bits[i]);
printf("\n");
sigemptyset(&add);
sigaddset(&add, SIGUSR1);
pthread_sigmask(SIG_BLOCK, &add, &old);
printf("after: ");
for (i=0; i<4; i++)
printf(" %08x", old.__bits[i]);
printf("\n");
return 0;
}
int main(void)
{
pthread_t thr;
void* ret;
printf("correct case: \n");
pthread_create(&thr, NULL, func, NULL);
pthread_join(thr, &ret);
printf("incorrect case: \n");
pthread_create(&thr, NULL, func2, NULL);
pthread_join(thr, &ret);
return 0;
}
>Fix:
/usr/src/lib/libc_r/uthread/uthread_sigmask.c has following code.
-----------------------------------------------------------------
int
_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset)
{
struct pthread *curthread = _get_curthread();
sigset_t sigset;
int ret = 0;
/* Check if the existing signal process mask is to be returned: */
if (oset != NULL) {
/* Return the current mask: */
*oset = curthread->sigmask; // (1)
}
/* Check if a new signal set was provided by the caller: */
if (set != NULL) {
(snip)
}
----------------------------------------------------
Then, if set == oset, set argument was override before use it at (1).
To introduce temporary variable fix this issue easily.
>Release-Note:
>Audit-Trail:
>Unformatted:
More information about the freebsd-threads
mailing list