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:
http://lists.apple.com/mailman/options/darwin-dev/email@hidden
This email sent to email@hidden