A Bug in pthread_cond_destroy?
A Bug in pthread_cond_destroy?
- Subject: A Bug in pthread_cond_destroy?
- From: "Kazuho Oku" <email@hidden>
- Date: Wed, 9 Jan 2008 16:25:51 +0900
Hi,
If this is not the right place to report bugs of libc, please tell me
the right mailing list. Thank you in advance, and sorry, if it is the
case.
I think I have found a bug in pthread_cond_destroy of Libc (with Mac
OS X 10.4.10).
Current implementation of pthread_cond_destroy does not check if
sigspending==0. Thus if pthread_cond_destroy is called from a thread
other than that called pthread_cond_signal, the destructor may return
0 even if pthread_cond_signal is still in work (i.e. sigspending !=
0), leading to memory corruption or an infinite loop in
pthread_cond_signal.
For example, in the following code, thread B would sometimes read from
and/or write to freed memory.
Thread A:
pthread_cond_wait(cond, &mutex);
while ((err = pthread_cond_destroy(cond)) != 0) {
assert(err == EBUSY);
usleep(1);
}
free(cond);
Thread B:
pthread_cond_signal(global_cond);
Note that the problem only arises when thread B does not lock the same
mutex as thread A when calling thread A (this is not a requirement in
POSIX threads).
Attached to this mail is a code that would reproduce this bug. It
sends and receives pthread_cond_signals and increment a counter.
It compiled without any compile time defines, the program prints the
counter incrementing infinitely.
But if compiled with -DCLEAR_MEM -DSIGNAL_WO_LOCK it would suddenly
stop due to memory corruption.
Or if compiled with -DAPPLE_TEST -DSIGNAL_WO_LOCK it would check the
value of sispending and print an assertion failure.
To reproduce the bug with the attached code, a dual processor system
might be a requirement.
--
Kazuho Oku
#include <assert.h>
#include <mach/semaphore.h>
#include <pthread.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#ifdef APPLE_TEST
typedef int32_t pthread_lock_t;
struct _pthread_mutex;
struct _pthread_cond
{
long sig; /* Unique signature for this structure */
pthread_lock_t lock; /* Used for internal mutex on structure */
semaphore_t sem; /* Kernel semaphore */
struct _pthread_cond *next, *prev; /* List of condition variables using
mutex */
struct _pthread_mutex *busy; /* mutex associated with variable */
uint32_t waiters:16, /* Number of threads waiting */
sigspending:16; /* Number of outstanding signals */
};
#endif
static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t cond_to_main = PTHREAD_COND_INITIALIZER;
static pthread_cond_t *cond_to_thread = NULL;
static void *my_thread(void *_1)
{
pthread_cond_t t[16];
int i;
#if APPLE_TEST
assert(sizeof(struct _pthread_cond) == sizeof(pthread_cond_t));
#endif
memset(t, 0x55, sizeof(t));
for (i = 0; ; i = (i + 1) & 15) {
assert(pthread_mutex_lock(&mutex) == 0);
assert(pthread_cond_init(t + i, NULL) == 0);
cond_to_thread = t + i;
assert(pthread_cond_signal(&cond_to_main) == 0);
assert(pthread_cond_wait(t + i, &mutex) == 0);
assert(pthread_cond_destroy(t + i) == 0);
#ifdef APPLE_TEST
assert(((struct _pthread_cond*)(t + i))->sigspending == 0);
#endif
assert(pthread_mutex_unlock(&mutex) == 0);
#ifdef CLEAR_MEM
memset(t + i, 0x55, sizeof(t[i]));
#endif
}
return NULL;
}
int main(int argc, char **argv)
{
pthread_t tid;
int i;
assert(pthread_mutex_lock(&mutex) == 0);
assert(pthread_create(&tid, NULL, my_thread, NULL) == 0);
for (i = 0; ; i++) {
pthread_cond_t *cc;
while (cond_to_thread == NULL) {
assert(pthread_cond_wait(&cond_to_main, &mutex) == 0);
}
cc = cond_to_thread;
cond_to_thread = NULL;
#ifdef SIGNAL_WO_LOCK
assert(pthread_mutex_unlock(&mutex) == 0);
#endif
printf("%d\n", i);
assert(pthread_cond_signal(cc) == 0);
#ifdef SIGNAL_WO_LOCK
assert(pthread_mutex_lock(&mutex) == 0);
#endif
}
return 0;
}
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden