Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [day] [month] [year] [list]
Message-ID: <20261105144541.5409-1-mailto.luca.kellermann@gmail.com>
Date: Thu,  5 Nov 2026 15:39:51 +0100
From: Luca Kellermann <mailto.luca.kellermann@...il.com>
To: musl@...ts.openwall.com
Subject: [PATCH] thrd_create: inherit signal mask from creating thread

POSIX.1-2024 requires that the new thread created by thrd_create()
inherits the signal mask from the creating thread, just like the new
thread created by pthread_create().

it seems like this was initially the case when thrd_create() was
implemented in commit 23614b0fcb4cd4d7b2e4148d3b1887b642169765. commit
04335d9260c076cf4d9264bd93dd3b06c237a639 then changed pthread_create()
to always block signals before starting new threads but restoring the
signal mask was only done for new threads started by pthread_create()
(start()), not for new threads started by thrd_create() (start_c11()).
this was before POSIX included threads.h, so it didn't violate any
specification back then (the C standard doesn't know signal masks).
---
The following program demonstrates the issue:

#include <pthread.h>
#include <signal.h>
#include <stdio.h>
#include <threads.h>
static int tf(void *a)
{
	sigset_t s;
	int i;
	return sigemptyset(&s) || pthread_sigmask(0, 0, &s)
		|| (i = sigismember(&s, SIGUSR1)) && i != 1
		|| printf("%s does%s inherit\n", (char *)a, i ? "n't" : "") < 0;
}
static void *pf(void *a)
{
	return tf(a) ? a : 0;
}
int main(void)
{
	sigset_t s;
	thrd_t t;
	int tr;
	pthread_t p;
	void *pr;
	return sigemptyset(&s) || sigaddset(&s, SIGUSR1)
		|| pthread_sigmask(SIG_UNBLOCK, &s, 0)
		|| thrd_create(&t, tf, "thrd_create") != thrd_success
		|| thrd_join(t, &tr) != thrd_success || tr
		|| pthread_create(&p, 0, pf, "pthread_create")
		|| pthread_join(p, &pr) || pr || fflush(stdout);
}

$ ./thrd_create-sigmask
thrd_create doesn't inherit
pthread_create does inherit

Should be:

$ ./thrd_create-sigmask
thrd_create does inherit
pthread_create does inherit

I used __restore_sigs() instead of a direct syscall like in start().
It does the same but seems simpler. Can be changed if consistency is
preferred.

 src/thread/pthread_create.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/thread/pthread_create.c b/src/thread/pthread_create.c
index 087f6206d5d64165bc54ae741e77099994ae96e0..e2e6838287fe5bb76e3d8c6bd7e4d065f67e9702 100644
--- a/src/thread/pthread_create.c
+++ b/src/thread/pthread_create.c
@@ -194,24 +194,25 @@
 static int start(void *p)
 {
 	struct start_args *args = p;
 	int state = args->control;
 	if (state) {
 		if (a_cas(&args->control, 1, 2)==1)
 			__wait(&args->control, 0, 2, 1);
 		if (args->control) {
 			__syscall(SYS_set_tid_address, &args->control);
 			for (;;) __syscall(SYS_exit, 0);
 		}
 	}
 	__syscall(SYS_rt_sigprocmask, SIG_SETMASK, &args->sig_mask, 0, _NSIG/8);
 	__pthread_exit(args->start_func(args->start_arg));
 	return 0;
 }
 
 static int start_c11(void *p)
 {
 	struct start_args *args = p;
 	int (*start)(void*) = (int(*)(void*)) args->start_func;
+	__restore_sigs(&args->sig_mask);
 	__pthread_exit((void *)(uintptr_t)start(args->start_arg));
 	return 0;
 }

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.