commit 073ef0f393ff4297e8d48a72f30a605c2d272289 (tree)
parent 111165513156d5732d85e5ccb52b9d8bded41ffa
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date: Tue, 6 Jan 2026 11:05:50 +0000
std.Thread: mask all signals before unmapping stack
As the comment explains, if a signal were to arrive between a detached
thread's `munmap` and `exit` calls, the signal handler would immediately
trigger SIGSEGV due to the stack being unmapped. To solve this, we need
to block all signals before entering this logic. The musl implementation
which this logic was ported from does this exact thing; that logic was
just lost when porting.
Notably, this would lead to a crash with no stack trace, because the
SIGSEGV handler would itself crash due to the missing stack.
Diffstat:
1 file changed, 4 insertions(+), 0 deletions(-)
diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig
@@ -1224,6 +1224,10 @@ const LinuxThreadImpl = struct {
/// Ported over from musl libc's pthread detached implementation:
/// https://github.com/ifduyue/musl/search?q=__unmapself
fn freeAndExit(self: *ThreadCompletion) noreturn {
+ // If a signal were delivered between SYS_munmap and SYS_exit, any installed signal
+ // handler would immediately segfault due to the stack being unmapped. To avoid this,
+ // we need to mask all signals before entering the inline asm.
+ posix.sigprocmask(std.posix.SIG.BLOCK, &std.os.linux.sigfillset(), null);
switch (target.cpu.arch) {
.x86 => asm volatile (
\\ movl $91, %%eax # SYS_munmap