authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-07 01:11:25+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-07 01:11:25+01:00
log1bef876636ab96449703ad2e8f9f22918546e99c
tree82f530c5feab4862e7c0b796d816ba2f3995409b
parentfa625e878f3f8f8b2dbc1d8ca0b761fb65326d02
parentbe0a77efd2aad5108d3357914cbc71f560ea0161

Merge pull request 'std.Thread: mask all signals before unmapping stack' (#30713) from detached-thread-exit-signal-race into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/30713 Reviewed-by: Andrew Kelley <andrew@ziglang.org>

4 files changed, 12 insertions(+), 6 deletions(-)

lib/std/Io/test.zig-4
......@@ -254,8 +254,6 @@ test "Group.cancel" {
254254}
255255
256256test "Group.concurrent" {
257 if (builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30096
258
259257 const io = testing.io;
260258
261259 var group: Io.Group = .init;
......@@ -421,8 +419,6 @@ test "Event" {
421419}
422420
423421test "recancel" {
424 if (builtin.os.tag == .linux and !builtin.link_libc) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30592
425
426422 const global = struct {
427423 fn worker(io: Io) Io.Cancelable!void {
428424 var dummy_event: Io.Event = .unset;
lib/std/Thread.zig+4
......@@ -1224,6 +1224,10 @@ const LinuxThreadImpl = struct {
12241224 /// Ported over from musl libc's pthread detached implementation:
12251225 /// https://github.com/ifduyue/musl/search?q=__unmapself
12261226 fn freeAndExit(self: *ThreadCompletion) noreturn {
1227 // If a signal were delivered between SYS_munmap and SYS_exit, any installed signal
1228 // handler would immediately segfault due to the stack being unmapped. To avoid this,
1229 // we need to mask all signals before entering the inline asm.
1230 posix.sigprocmask(std.posix.SIG.BLOCK, &std.os.linux.sigfillset(), null);
12271231 switch (target.cpu.arch) {
12281232 .x86 => asm volatile (
12291233 \\ movl $91, %%eax # SYS_munmap
lib/std/crypto/argon2.zig-2
......@@ -907,8 +907,6 @@ test "kdf" {
907907}
908908
909909test "phc format hasher" {
910 if (true) return error.SkipZigTest; // https://codeberg.org/ziglang/zig/issues/30682
911
912910 const allocator = std.testing.allocator;
913911 const password = "testpass";
914912 const io = std.testing.io;
lib/std/debug.zig+8
......@@ -532,6 +532,10 @@ pub fn defaultPanic(msg: []const u8, first_trace_addr: ?usize) noreturn {
532532 else => {},
533533 }
534534
535 // Don't try to cancel during a panic. No need to re-enable cancelation,
536 // because the panic handler doesn't return.
537 _ = std.Options.debug_io.swapCancelProtection(.blocked);
538
535539 if (enable_segfault_handler) {
536540 // If a segfault happens while panicking, we want it to actually segfault, not trigger
537541 // the handler.
......@@ -1533,6 +1537,10 @@ fn handleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContextPtr) noret
15331537}
15341538
15351539pub fn defaultHandleSegfault(addr: ?usize, name: []const u8, opt_ctx: ?CpuContextPtr) noreturn {
1540 // Don't try to cancel during a segfault. No need to re-enable cancelation,
1541 // because the segfault handler doesn't return.
1542 _ = std.Options.debug_io.swapCancelProtection(.blocked);
1543
15361544 // There is very similar logic to the following in `defaultPanic`.
15371545 switch (panic_stage) {
15381546 0 => {