motiejus/zig

fork of https://codeberg.org/ziglang/zig
git clone https://git.jakstys.lt/motiejus/zig.git
Log | Tree | Refs | README | LICENSE

commit 27611c10f8dc6a58161699a30a573459d855aede (tree)
parent 9b1eaad13fd331c4c2135f15ab9512b9e2342ff2
Author: Alex Rønne Petersen <alex@alexrp.com>
Date:   Wed,  1 Apr 2026 11:38:06 +0200

Merge pull request 'LinuxThreadImpl fixups' (#31716) from blblack/zig:linux-thread-childtid into master

Reviewed-on: https://codeberg.org/ziglang/zig/pulls/31716
Reviewed-by: Alex Rønne Petersen <alex@alexrp.com>

Diffstat:
Mlib/std/Thread.zig | 7++++++-
Mlib/std/os/linux.zig | 5+++++
2 files changed, 11 insertions(+), 1 deletion(-)

diff --git a/lib/std/Thread.zig b/lib/std/Thread.zig @@ -1147,6 +1147,11 @@ 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 we do not reset the child_tidptr to null here, the kernel would later write the + // value zero to that address, which is inside the block we're unmapping below, after + // our thread exits. This can sometimes corrupt memory in other mmap blocks from + // unrelated concurrent threads. + _ = linux.set_tid_address(null); // 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. @@ -1484,7 +1489,7 @@ const LinuxThreadImpl = struct { } // Prepare the TLS segment and prepare a user_desc struct when needed on x86 - var tls_ptr = linux.tls.prepareArea(mapped[tls_offset..]); + var tls_ptr = linux.tls.prepareArea(mapped[tls_offset..][0..linux.tls.area_desc.size]); var user_desc: if (target.cpu.arch == .x86) linux.user_desc else void = undefined; if (target.cpu.arch == .x86) { defer tls_ptr = @intFromPtr(&user_desc); diff --git a/lib/std/os/linux.zig b/lib/std/os/linux.zig @@ -1584,6 +1584,11 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize { return syscall2(.clone, flags, child_stack_ptr); } +/// This call cannot fail, and the return value is the caller's thread id +pub fn set_tid_address(tidptr: ?*pid_t) pid_t { + return @intCast(@as(u32, @truncate(syscall1(.set_tid_address, @intFromPtr(tidptr))))); +} + pub fn close(fd: fd_t) usize { return syscall1(.close, @as(usize, @bitCast(@as(isize, fd)))); }