]> granicus.if.org Git - musl/commitdiff
fix signal masking race in pthread_create with priority attributes
authorRich Felker <dalias@aerifal.cx>
Thu, 7 Sep 2017 00:37:19 +0000 (20:37 -0400)
committerRich Felker <dalias@aerifal.cx>
Thu, 7 Sep 2017 00:37:19 +0000 (20:37 -0400)
if the parent thread was able to set the new thread's priority before
it reached the check for 'startlock', the new thread failed to restore
its signal mask and thus ran with all signals blocked.

concept for patch by Sergei, who reported the issue; unnecessary
changes were removed and comments added since the whole 'startlock'
thing is non-idiomatic and confusing. eventually it should be replaced
with use of idiomatic synchronization primitives.

src/thread/pthread_create.c

index 49f2f7296804be25efe16ce57f6280c66751eda9..6cbf85b32e052342032a09fc2e0f43530a9b7f25 100644 (file)
@@ -131,9 +131,14 @@ void __do_cleanup_pop(struct __ptcb *cb)
 static int start(void *p)
 {
        pthread_t self = p;
+       /* States for startlock:
+        * 0 = no need for start sync
+        * 1 = waiting for parent to do work
+        * 2 = failure in parent, child must abort
+        * 3 = success in parent, child must restore sigmask */
        if (self->startlock[0]) {
                __wait(self->startlock, 0, 1, 1);
-               if (self->startlock[0]) {
+               if (self->startlock[0] == 2) {
                        self->detached = 2;
                        pthread_exit(0);
                }
@@ -295,7 +300,7 @@ int __pthread_create(pthread_t *restrict res, const pthread_attr_t *restrict att
        if (do_sched) {
                ret = __syscall(SYS_sched_setscheduler, new->tid,
                        attr._a_policy, &attr._a_prio);
-               a_store(new->startlock, ret<0 ? 2 : 0);
+               a_store(new->startlock, ret<0 ? 2 : 3);
                __wake(new->startlock, 1, 1);
                if (ret < 0) return -ret;
        }