fix false ownership of stdio FILEs due to tid reuse
authorRich Felker <dalias@aerifal.cx>
Sun, 24 Aug 2014 03:35:10 +0000 (23:35 -0400)
committerRich Felker <dalias@aerifal.cx>
Sun, 24 Aug 2014 03:35:10 +0000 (23:35 -0400)
this is analogous commit fffc5cda10e0c5c910b40f7be0d4fa4e15bb3f48
which fixed the corresponding issue for mutexes.

the robust list can't be used here because the locks do not share a
common layout with mutexes. at some point it may make sense to simply
incorporate a mutex object into the FILE structure and use it, but
that would be a much more invasive change, and it doesn't mesh well
with the current design that uses a simpler code path for internal
locking and pulls in the recursive-mutex-like code when the flockfile
API is used explicitly.

src/internal/pthread_impl.h
src/internal/stdio_impl.h
src/stdio/fclose.c
src/stdio/ftrylockfile.c
src/stdio/funlockfile.c
src/thread/pthread_create.c

index 4de6637..74c62cc 100644 (file)
@@ -44,6 +44,7 @@ struct pthread {
        int exitlock[2];
        int startlock[2];
        unsigned long sigmask[_NSIG/8/sizeof(long)];
+       void *stdio_locks;
 };
 
 struct __timer {
index 79be9fd..d659522 100644 (file)
@@ -46,6 +46,7 @@ struct _IO_FILE {
        void *mustbezero_2;
        unsigned char *shend;
        off_t shlim, shcnt;
+       FILE *prev_locked, *next_locked;
 };
 
 size_t __stdio_read(FILE *, unsigned char *, size_t);
index 38e8a1e..317b3c9 100644 (file)
@@ -1,4 +1,8 @@
 #include "stdio_impl.h"
+#include "libc.h"
+
+static void dummy(FILE *f) { }
+weak_alias(dummy, __unlist_locked_file);
 
 int fclose(FILE *f)
 {
@@ -7,6 +11,8 @@ int fclose(FILE *f)
        
        FFINALLOCK(f);
 
+       __unlist_locked_file(f);
+
        if (!(perm = f->flags & F_PERM)) {
                OFLLOCK();
                if (f->prev) f->prev->next = f->next;
index 56cccaf..6f9a4b8 100644 (file)
@@ -2,9 +2,26 @@
 #include "pthread_impl.h"
 #include <limits.h>
 
+void __do_orphaned_stdio_locks()
+{
+       FILE *f;
+       for (f=__pthread_self()->stdio_locks; f; f=f->next_locked)
+               a_store(&f->lock, 0x40000000);
+}
+
+void __unlist_locked_file(FILE *f)
+{
+       if (f->lockcount) {
+               if (f->next_locked) f->next_locked->prev_locked = f->prev_locked;
+               if (f->prev_locked) f->prev_locked->next_locked = f->next_locked;
+               else __pthread_self()->stdio_locks = f->next_locked;
+       }
+}
+
 int ftrylockfile(FILE *f)
 {
-       int tid = __pthread_self()->tid;
+       pthread_t self = __pthread_self();
+       int tid = self->tid;
        if (f->lock == tid) {
                if (f->lockcount == LONG_MAX)
                        return -1;
@@ -15,5 +32,8 @@ int ftrylockfile(FILE *f)
        if (f->lock || a_cas(&f->lock, 0, tid))
                return -1;
        f->lockcount = 1;
+       f->prev_locked = 0;
+       f->next_locked = self->stdio_locks;
+       self->stdio_locks = f;
        return 0;
 }
index f8a2a07..30a07ef 100644 (file)
@@ -1,7 +1,15 @@
 #include "stdio_impl.h"
 #include "pthread_impl.h"
 
+void __unlist_locked_file(FILE *);
+
 void funlockfile(FILE *f)
 {
-       if (!--f->lockcount) __unlockfile(f);
+       if (f->lockcount == 1) {
+               __unlist_locked_file(f);
+               f->lockcount = 0;
+               __unlockfile(f);
+       } else {
+               f->lockcount--;
+       }
 }
index 1601614..e441bda 100644 (file)
@@ -12,6 +12,7 @@ weak_alias(dummy_0, __acquire_ptc);
 weak_alias(dummy_0, __release_ptc);
 weak_alias(dummy_0, __pthread_tsd_run_dtors);
 weak_alias(dummy_0, __do_private_robust_list);
+weak_alias(dummy_0, __do_orphaned_stdio_locks);
 
 _Noreturn void pthread_exit(void *result)
 {
@@ -66,6 +67,7 @@ _Noreturn void pthread_exit(void *result)
        }
 
        __do_private_robust_list();
+       __do_orphaned_stdio_locks();
 
        if (self->detached && self->map_base) {
                /* Detached threads must avoid the kernel clear_child_tid