This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH] Fix possible deadlock in stdio locking code
- From: Siddhesh Poyarekar <spoyarek at redhat dot com>
- To: Andreas Schwab <schwab at redhat dot com>
- Cc: libc-alpha at sourceware dot org
- Date: Mon, 7 Nov 2011 18:00:56 +0530
- Subject: Re: [PATCH] Fix possible deadlock in stdio locking code
- References: <20111018140922.GA5701@spoyarek.pnq.redhat.com><m3vcrmgxcc.fsf@hase.home>
On Tue, Oct 18, 2011 at 04:58:59PM +0200, Andreas Schwab wrote:
> Siddhesh Poyarekar <spoyarek@redhat.com> writes:
>
> > 1) thread A pushes the cleanup callback flush_cleanup using
> > _IO_cleanup_region_start_noarg()
> >
> > 2) Some other thread calls pthread_cancel on thread A before it gets
> > to call _IO_lock_lock(list_all_lock)
>
> That pthread_cancel call will have no effect until the next cancellation
> point.
>
I have come up with a reproducer for this (at the end of this
email). I have verified that the fix in my original submission:
http://sourceware.org/ml/libc-alpha/2011-10/msg00036.html
fixes this problem. It cannot be fixed within _IO_flush_all_lockp() in
libio/genops.c due to the way pthread_cleanup_push and
pthread_cleanup_pop have been implemented.
--
Siddhesh
The reproducer:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
pthread_mutex_t mutex;
void *do_fork(void *foo)
{
while(1) {
int child = fork();
if (child == 0)
exit(0);
waitpid(-1, NULL, 0);
sleep(1);
}
}
void *do_io(void *foo)
{
FILE *f = fopen("/tmp/foo", "w+");
if (f)
fprintf(f, "hellllllllllllllllllllllloooooooooooooo");
fcloseall();
}
int main(int argc, char **argv)
{
pthread_t fork_thr;
pthread_create(&fork_thr, NULL, do_fork, NULL);
pthread_mutex_init(&mutex, NULL);
while (1) {
pthread_t io_thr;
pthread_create(&io_thr, NULL, do_io, NULL);
pthread_cancel(io_thr);
pthread_join(io_thr, NULL);
}
}