fix regression in pthread_exit
authorRich Felker <dalias@aerifal.cx>
Fri, 20 Nov 2020 15:43:20 +0000 (10:43 -0500)
committerRich Felker <dalias@aerifal.cx>
Fri, 20 Nov 2020 15:43:20 +0000 (10:43 -0500)
commit d26e0774a59bb7245b205bc8e7d8b35cc2037095 moved the detach state
transition at exit before the thread list lock was taken. this
inadvertently allowed pthread_join to race to take the thread list
lock first, and proceed with unmapping of the exiting thread's memory.

we could fix this by just revering the offending commit and instead
performing __vm_wait unconditionally before taking the thread list
lock, but that may be costly. instead, bring back the old DT_EXITING
vs DT_EXITED state distinction that was removed in commit
8f11e6127fe93093f81a52b15bb1537edc3fc8af, and don't transition to
DT_EXITED (a value of 0, which is what pthread_join waits for) until
after the lock has been taken.

src/internal/pthread_impl.h
src/thread/pthread_create.c

index 1322a6a..de2b9d8 100644 (file)
@@ -68,7 +68,8 @@ struct pthread {
 };
 
 enum {
-       DT_EXITING = 0,
+       DT_EXITED = 0,
+       DT_EXITING,
        DT_JOINABLE,
        DT_DETACHED,
 };
index 250cd0a..6f187ee 100644 (file)
@@ -156,6 +156,7 @@ _Noreturn void __pthread_exit(void *result)
        }
 
        /* Wake any joiner. */
+       a_store(&self->detach_state, DT_EXITED);
        __wake(&self->detach_state, 1, 1);
 
        /* After the kernel thread exits, its tid may be reused. Clear it