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 4de663785c0473efc38446f17a9f7fa36981b197..74c62cce81774cdcdbcb9f0f586788c6a98fb9d4 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 79be9fdb0d49c96093b6a86002b9935de647b7fd..d659522fde90a42e96eaa3f36d837f796f953465 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 38e8a1e39dae99255328d97150180652afde9fb2..317b3c901e7dfd066bfcb3a236b89c2a8b8e02cd 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 56cccafdc19fc3d7f60d8ae123aa479d3905d6e7..6f9a4b8892407f9efe636cc0e8fa578f8d13160d 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 f8a2a071e64596b00e52940d47d94ca7ec2bee80..30a07ef4b37433d46ec5ef44e9c67001a5841e7e 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 1601614a32f36e99ca44d8d48e607686e74c4d25..e441bdac84b68d4204a380e552d29251861e4dd9 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