From bab66235b94643e10dfc58db38c8ea4b8be46c37 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 8 Mar 2020 13:45:16 +0100 Subject: [PATCH 01/11] stage1: Remove fflush on file open for reading On NetBSD this caused the libuserland compilation to fail. Closes #3719 --- src/os.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/os.cpp b/src/os.cpp index 351b61cd66..872c0270f1 100644 --- a/src/os.cpp +++ b/src/os.cpp @@ -1161,9 +1161,6 @@ Error os_update_file(Buf *src_path, Buf *dst_path) { fclose(dst_libc_file); return err; } - if (fflush(src_libc_file) == -1) { - return ErrorUnexpected; - } if (fflush(dst_libc_file) == -1) { return ErrorUnexpected; } From 2f21c8f5ba2e73c1a674b481fd2a8ce87726c14c Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 8 Mar 2020 13:52:51 +0100 Subject: [PATCH 02/11] stage1: Link pthread on NetBSD --- src/link.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/link.cpp b/src/link.cpp index b340206b14..6c61ee040a 100644 --- a/src/link.cpp +++ b/src/link.cpp @@ -1799,7 +1799,9 @@ static void construct_linker_job_elf(LinkJob *lj) { lj->args.append("-lm"); } - if (g->zig_target->os == OsFreeBSD) { + if (g->zig_target->os == OsFreeBSD || + g->zig_target->os == OsNetBSD) + { lj->args.append("-lpthread"); } } else if (target_is_glibc(g->zig_target)) { From 27344464edea0b6acf4dfc78d71700d67a3f3968 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Sun, 8 Mar 2020 16:04:02 +0100 Subject: [PATCH 03/11] std: Add missing C defines for NetBSD --- lib/std/c/netbsd.zig | 9 +++++++++ lib/std/debug.zig | 2 ++ lib/std/os.zig | 30 ++++++++++++++++++++++++++++++ lib/std/os/bits/netbsd.zig | 29 +++++++++++++++++++++++------ 4 files changed, 64 insertions(+), 6 deletions(-) diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index c253362ac1..f9b2510f84 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -1,4 +1,6 @@ const std = @import("../std.zig"); +const builtin = std.builtin; + usingnamespace std.c; extern "c" fn __errno() *c_int; @@ -7,6 +9,13 @@ pub const _errno = __errno; pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; +pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; +pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; + +pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int; +pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int; +pub extern "c" fn __clock_getres50(clk_id: c_int, tp: *timespec) c_int; + pub const pthread_mutex_t = extern struct { ptm_magic: c_uint = 0x33330003, ptm_errorcheck: padded_spin_t = 0, diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 5600990924..67526ac829 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -654,6 +654,8 @@ pub fn openSelfDebugInfo(allocator: *mem.Allocator) anyerror!DebugInfo { switch (builtin.os.tag) { .linux, .freebsd, + .netbsd, + .dragonfly, .macosx, .windows, => return DebugInfo.init(allocator), diff --git a/lib/std/os.zig b/lib/std/os.zig index 2dec2c4c1d..f03aa96cf9 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2542,6 +2542,17 @@ pub fn fstat(fd: fd_t) FStatError!Stat { } } + if (std.Target.current.os.tag == .netbsd) { + switch (errno(system.__fstat50(fd, &stat))) { + 0 => return stat, + EINVAL => unreachable, + EBADF => unreachable, // Always a race condition. + ENOMEM => return error.SystemResources, + EACCES => return error.AccessDenied, + else => |err| return unexpectedErrno(err), + } + } + switch (errno(system.fstat(fd, &stat))) { 0 => return stat, EINVAL => unreachable, @@ -3401,6 +3412,16 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { } return; } + + if (std.Target.current.os.tag == .netbsd) { + switch (errno(system.__clock_gettime50(clk_id, tp))) { + 0 => return, + EFAULT => unreachable, + EINVAL => return error.UnsupportedClock, + else => |err| return unexpectedErrno(err), + } + } + switch (errno(system.clock_gettime(clk_id, tp))) { 0 => return, EFAULT => unreachable, @@ -3423,6 +3444,15 @@ pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { return; } + if (std.Target.current.os.tag == .netbsd) { + switch (errno(system.__clock_getres50(clk_id, res))) { + 0 => return, + EFAULT => unreachable, + EINVAL => return error.UnsupportedClock, + else => |err| return unexpectedErrno(err), + } + } + switch (errno(system.clock_getres(clk_id, res))) { 0 => return, EFAULT => unreachable, diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index 4abd4c8c5e..c99d1b3b38 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -1,9 +1,12 @@ const std = @import("../../std.zig"); const maxInt = std.math.maxInt; -pub const fd_t = c_int; -pub const pid_t = c_int; -pub const mode_t = c_uint; +pub const fd_t = i32; +pub const pid_t = i32; +pub const mode_t = u32; +pub const ino_t = u64; +pub const off_t = i64; +pub const socklen_t = u32; /// Renamed from `kevent` to `Kevent` to avoid conflict with function name. pub const Kevent = extern struct { @@ -68,9 +71,6 @@ pub const msghdr_const = extern struct { msg_flags: i32, }; -pub const off_t = i64; -pub const ino_t = u64; - /// Renamed to Stat to not conflict with the stat function. /// atime, mtime, and ctime have functions to return `timespec`, /// because although this is a POSIX API, the layout and names of @@ -816,6 +816,23 @@ pub fn S_IWHT(m: u32) bool { return m & S_IFMT == S_IFWHT; } +/// Magic value that specify the use of the current working directory +/// to determine the target of relative file paths in the openat() and +/// similar syscalls. +pub const AT_FDCWD = -100; + +/// Check access using effective user and group ID +pub const AT_EACCESS = 0x0100; + +/// Do not follow symbolic links +pub const AT_SYMLINK_NOFOLLOW = 0x0200; + +/// Follow symbolic link +pub const AT_SYMLINK_FOLLOW = 0x0400; + +/// Remove directory instead of file +pub const AT_REMOVEDIR = 0x0800; + pub const HOST_NAME_MAX = 255; /// dummy for IP From 336ed03f0f4ffde8e60fb8b4859c0c2158511338 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 18:51:10 +0100 Subject: [PATCH 04/11] debug: Accept relative paths in mapWholeFile --- lib/std/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 67526ac829..8af265b5ac 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1049,7 +1049,7 @@ const MachoSymbol = struct { fn mapWholeFile(path: []const u8) ![]align(mem.page_size) const u8 { noasync { - const file = try fs.openFileAbsolute(path, .{ .always_blocking = true }); + const file = try fs.cwd().openFile(path, .{ .always_blocking = true }); defer file.close(); const file_len = try math.cast(usize, try file.getEndPos()); From 761602e3e84afee1a77daf9f850c67cb8e25f7ed Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 18:54:14 +0100 Subject: [PATCH 05/11] std: Use getdents on all the BSDs * Use the correct versioned libc calls to avoid nasty surprises --- lib/std/c/netbsd.zig | 5 ++--- lib/std/fs.zig | 10 ++++------ lib/std/os.zig | 11 +++++++++++ 3 files changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/std/c/netbsd.zig b/lib/std/c/netbsd.zig index f9b2510f84..fd70220603 100644 --- a/lib/std/c/netbsd.zig +++ b/lib/std/c/netbsd.zig @@ -6,15 +6,14 @@ usingnamespace std.c; extern "c" fn __errno() *c_int; pub const _errno = __errno; -pub extern "c" fn getdents(fd: c_int, buf_ptr: [*]u8, nbytes: usize) usize; -pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; - pub const dl_iterate_phdr_callback = extern fn (info: *dl_phdr_info, size: usize, data: ?*c_void) c_int; pub extern "c" fn dl_iterate_phdr(callback: dl_iterate_phdr_callback, data: ?*c_void) c_int; pub extern "c" fn __fstat50(fd: fd_t, buf: *Stat) c_int; pub extern "c" fn __clock_gettime50(clk_id: c_int, tp: *timespec) c_int; pub extern "c" fn __clock_getres50(clk_id: c_int, tp: *timespec) c_int; +pub extern "c" fn __getdents30(fd: c_int, buf_ptr: [*]u8, nbytes: usize) c_int; +pub extern "c" fn __sigaltstack14(ss: ?*stack_t, old_ss: ?*stack_t) c_int; pub const pthread_mutex_t = extern struct { ptm_magic: c_uint = 0x33330003, diff --git a/lib/std/fs.zig b/lib/std/fs.zig index 333419d02b..c84f87daec 100644 --- a/lib/std/fs.zig +++ b/lib/std/fs.zig @@ -339,12 +339,10 @@ pub const Dir = struct { fn nextBsd(self: *Self) !?Entry { start_over: while (true) { if (self.index >= self.end_index) { - const rc = os.system.getdirentries( - self.dir.fd, - &self.buf, - self.buf.len, - &self.seek, - ); + const rc = if (builtin.os.tag == .netbsd) + os.system.__getdents30(self.dir.fd, &self.buf, self.buf.len) + else + os.system.getdents(self.dir.fd, &self.buf, self.buf.len); switch (os.errno(rc)) { 0 => {}, os.EBADF => unreachable, // Dir is invalid or was opened without iteration ability diff --git a/lib/std/os.zig b/lib/std/os.zig index f03aa96cf9..4e25b254ea 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -3522,6 +3522,17 @@ pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { if (builtin.os.tag == .windows or builtin.os.tag == .uefi or builtin.os.tag == .wasi) @compileError("std.os.sigaltstack not available for this target"); + if (std.Target.current.os.tag == .netbsd) { + switch (errno(system.__sigaltstack14(ss, old_ss))) { + 0 => return, + EFAULT => unreachable, + EINVAL => unreachable, + ENOMEM => return error.SizeTooSmall, + EPERM => return error.PermissionDenied, + else => |err| return unexpectedErrno(err), + } + } + switch (errno(system.sigaltstack(ss, old_ss))) { 0 => return, EFAULT => unreachable, From cda73c3c189924bc085d1e89a9592d6632365c90 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 18:55:45 +0100 Subject: [PATCH 06/11] std: Add missing C bits and defines for NetBSD --- lib/std/os/bits/netbsd.zig | 162 +++++++++++++++++++++++++++++++------ 1 file changed, 138 insertions(+), 24 deletions(-) diff --git a/lib/std/os/bits/netbsd.zig b/lib/std/os/bits/netbsd.zig index c99d1b3b38..a26fdee2a9 100644 --- a/lib/std/os/bits/netbsd.zig +++ b/lib/std/os/bits/netbsd.zig @@ -25,6 +25,65 @@ pub const dl_phdr_info = extern struct { dlpi_phnum: u16, }; +pub const addrinfo = extern struct { + flags: i32, + family: i32, + socktype: i32, + protocol: i32, + addrlen: socklen_t, + canonname: ?[*:0]u8, + addr: ?*sockaddr, + next: ?*addrinfo, +}; + +pub const EAI = extern enum(c_int) { + /// address family for hostname not supported + ADDRFAMILY = 1, + + /// name could not be resolved at this time + AGAIN = 2, + + /// flags parameter had an invalid value + BADFLAGS = 3, + + /// non-recoverable failure in name resolution + FAIL = 4, + + /// address family not recognized + FAMILY = 5, + + /// memory allocation failure + MEMORY = 6, + + /// no address associated with hostname + NODATA = 7, + + /// name does not resolve + NONAME = 8, + + /// service not recognized for socket type + SERVICE = 9, + + /// intended socket type was not recognized + SOCKTYPE = 10, + + /// system error returned in errno + SYSTEM = 11, + + /// invalid value for hints + BADHINTS = 12, + + /// resolved protocol is unknown + PROTOCOL = 13, + + /// argument buffer overflow + OVERFLOW = 14, + + _, +}; + +pub const EAI_MAX = 15; + pub const msghdr = extern struct { /// optional address msg_name: ?*sockaddr, @@ -122,7 +181,6 @@ pub const dirent = extern struct { d_reclen: u16, d_namlen: u16, d_type: u8, - d_off: i64, d_name: [512]u8, pub fn reclen(self: dirent) u16 { @@ -146,7 +204,7 @@ pub const sockaddr = extern struct { pub const sockaddr_in = extern struct { len: u8 = @sizeOf(sockaddr_in), - family: sa_family_t, + family: sa_family_t = AF_INET, port: in_port_t, addr: u32, zero: [8]u8 = [8]u8{ 0, 0, 0, 0, 0, 0, 0, 0 }, @@ -154,7 +212,7 @@ pub const sockaddr_in = extern struct { pub const sockaddr_in6 = extern struct { len: u8 = @sizeOf(sockaddr_in6), - family: sa_family_t, + family: sa_family_t = AF_INET6, port: in_port_t, flowinfo: u32, addr: [16]u8, @@ -167,12 +225,27 @@ pub const sockaddr_un = extern struct { len: u8 = @sizeOf(sockaddr_un), /// AF_LOCAL - family: sa_family_t, + family: sa_family_t = AF_LOCAL, /// path name path: [104]u8, }; +/// get address to use bind() +pub const AI_PASSIVE = 0x00000001; + +/// fill ai_canonname +pub const AI_CANONNAME = 0x00000002; + +/// prevent host name resolution +pub const AI_NUMERICHOST = 0x00000004; + +/// prevent service name resolution +pub const AI_NUMERICSERV = 0x00000008; + +/// only if any address is assigned +pub const AI_ADDRCONFIG = 0x00000400; + pub const CTL_KERN = 1; pub const CTL_DEBUG = 5; @@ -274,30 +347,71 @@ pub const X_OK = 1; // test for execute or search permission pub const W_OK = 2; // test for write permission pub const R_OK = 4; // test for read permission -pub const O_RDONLY = 0x0000; -pub const O_WRONLY = 0x0001; -pub const O_RDWR = 0x0002; -pub const O_ACCMODE = 0x0003; +/// open for reading only +pub const O_RDONLY = 0x00000000; -pub const O_CREAT = 0x0200; -pub const O_EXCL = 0x0800; -pub const O_NOCTTY = 0x8000; -pub const O_TRUNC = 0x0400; -pub const O_APPEND = 0x0008; -pub const O_NONBLOCK = 0x0004; -pub const O_DSYNC = 0x00010000; -pub const O_SYNC = 0x0080; -pub const O_RSYNC = 0x00020000; -pub const O_DIRECTORY = 0x00080000; +/// open for writing only +pub const O_WRONLY = 0x00000001; + +/// open for reading and writing +pub const O_RDWR = 0x00000002; + +/// mask for above modes +pub const O_ACCMODE = 0x00000003; + +/// no delay +pub const O_NONBLOCK = 0x00000004; + +/// set append mode +pub const O_APPEND = 0x00000008; + +/// open with shared file lock +pub const O_SHLOCK = 0x00000010; + +/// open with exclusive file lock +pub const O_EXLOCK = 0x00000020; + +/// signal pgrp when data ready +pub const O_ASYNC = 0x00000040; + +/// synchronous writes +pub const O_SYNC = 0x00000080; + +/// don't follow symlinks on the last pub const O_NOFOLLOW = 0x00000100; + +/// create if nonexistent +pub const O_CREAT = 0x00000200; + +/// truncate to zero length +pub const O_TRUNC = 0x00000400; + +/// error if already exists +pub const O_EXCL = 0x00000800; + +/// don't assign controlling terminal +pub const O_NOCTTY = 0x00008000; + +/// write: I/O data completion +pub const O_DSYNC = 0x00010000; + +/// read: I/O completion as for write +pub const O_RSYNC = 0x00020000; + +/// use alternate i/o semantics +pub const O_ALT_IO = 0x00040000; + +/// direct I/O hint +pub const O_DIRECT = 0x00080000; + +/// fail if not a directory +pub const O_DIRECTORY = 0x00200000; + +/// set close on exec pub const O_CLOEXEC = 0x00400000; -pub const O_ASYNC = 0x0040; -pub const O_DIRECT = 0x00080000; -pub const O_NOATIME = 0; -pub const O_PATH = 0; -pub const O_TMPFILE = 0; -pub const O_NDELAY = O_NONBLOCK; +/// skip search permission checks +pub const O_SEARCH = 0x00800000; pub const F_DUPFD = 0; pub const F_GETFD = 1; From 09a5f172f876c20e52d6cc0c634d15ddeee8f1ff Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 19:50:29 +0100 Subject: [PATCH 07/11] std: Different thread stack allocation for NetBSD * NetBSD is stricter than other OSs and doesn't allow mprotect to mark a non-accessible region as RW * Fix mprotect call over the whole stack, oops --- lib/std/thread.zig | 85 +++++++++++++++++++++++++++++++++------------- 1 file changed, 61 insertions(+), 24 deletions(-) diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 596a8f3cd9..4b28d7cf6d 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -292,32 +292,69 @@ pub const Thread = struct { l += tls_img.alloc_size; } } - break :blk l; + // Round the size to the page size. + break :blk mem.alignForward(l, mem.page_size); }; - // Map the whole stack with no rw permissions to avoid committing the - // whole region right away - const mmap_slice = os.mmap( - null, - mem.alignForward(mmap_len, mem.page_size), - os.PROT_NONE, - os.MAP_PRIVATE | os.MAP_ANONYMOUS, - -1, - 0, - ) catch |err| switch (err) { - error.MemoryMappingNotSupported => unreachable, - error.AccessDenied => unreachable, - error.PermissionDenied => unreachable, - else => |e| return e, - }; - errdefer os.munmap(mmap_slice); - // Map everything but the guard page as rw - os.mprotect( - mmap_slice, - os.PROT_READ | os.PROT_WRITE, - ) catch |err| switch (err) { - error.AccessDenied => unreachable, - else => |e| return e, + const mmap_slice = mem: { + if (std.Target.current.os.tag != .netbsd) { + // Map the whole stack with no rw permissions to avoid + // committing the whole region right away + const mmap_slice = os.mmap( + null, + mmap_len, + os.PROT_NONE, + os.MAP_PRIVATE | os.MAP_ANONYMOUS, + -1, + 0, + ) catch |err| switch (err) { + error.MemoryMappingNotSupported => unreachable, + error.AccessDenied => unreachable, + error.PermissionDenied => unreachable, + else => |e| return e, + }; + errdefer os.munmap(mmap_slice); + + // Map everything but the guard page as rw + os.mprotect( + mmap_slice[guard_end_offset..], + os.PROT_READ | os.PROT_WRITE, + ) catch |err| switch (err) { + error.AccessDenied => unreachable, + else => |e| return e, + }; + + break :mem mmap_slice; + } else { + // NetBSD mprotect is very strict and doesn't allow to "upgrade" + // a PROT_NONE mapping to a RW one so let's allocate everything + // right away + const mmap_slice = os.mmap( + null, + mmap_len, + os.PROT_READ | os.PROT_WRITE, + os.MAP_PRIVATE | os.MAP_ANONYMOUS, + -1, + 0, + ) catch |err| switch (err) { + error.MemoryMappingNotSupported => unreachable, + error.AccessDenied => unreachable, + error.PermissionDenied => unreachable, + else => |e| return e, + }; + errdefer os.munmap(mmap_slice); + + // Remap the guard page with no permissions + os.mprotect( + mmap_slice[0..guard_end_offset], + os.PROT_NONE, + ) catch |err| switch (err) { + error.AccessDenied => unreachable, + else => |e| return e, + }; + + break :mem mmap_slice; + } }; const mmap_addr = @ptrToInt(mmap_slice.ptr); From b21d3535a53d03578705f5458c02afc37922d39f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 20:12:10 +0100 Subject: [PATCH 08/11] std: Fix parameters for pthread_attr_setstack The guard page size shouldn't be taken into account, pthread is only interested in the usable area. --- lib/std/thread.zig | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/std/thread.zig b/lib/std/thread.zig index 4b28d7cf6d..f2b27caa97 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -375,7 +375,12 @@ pub const Thread = struct { if (c.pthread_attr_init(&attr) != 0) return error.SystemResources; defer assert(c.pthread_attr_destroy(&attr) == 0); - assert(c.pthread_attr_setstack(&attr, mmap_slice.ptr, stack_end_offset) == 0); + // Tell pthread where the effective stack start is and its size + assert(c.pthread_attr_setstack( + &attr, + mmap_slice.ptr + guard_end_offset, + stack_end_offset - guard_end_offset, + ) == 0); const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg)); switch (err) { From d6739b1397b32dae936432d9da17e740477898eb Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 23:26:21 +0100 Subject: [PATCH 09/11] std: Fix undefined field error --- lib/std/debug.zig | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/std/debug.zig b/lib/std/debug.zig index 8af265b5ac..94475515e7 100644 --- a/lib/std/debug.zig +++ b/lib/std/debug.zig @@ -1623,7 +1623,7 @@ pub const ModuleDebugInfo = switch (builtin.os.tag) { }; } }, - .linux, .freebsd => struct { + .linux, .netbsd, .freebsd, .dragonfly => struct { base_address: usize, dwarf: DW.DwarfInfo, mapped_memory: []const u8, From c3f93be00cd516a561b32df4c68b5ed01e851645 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Mon, 23 Mar 2020 23:26:34 +0100 Subject: [PATCH 10/11] std: Tell pthread the guard page size is zero On NetBSD this is needed to avoid crashes in pthread_join as the default value for the guard page size is not ignored even though a custom stack address is specified. --- lib/std/c.zig | 1 + lib/std/thread.zig | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/lib/std/c.zig b/lib/std/c.zig index 43b3d7f317..0d8aa13dec 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -184,6 +184,7 @@ pub extern "c" fn futimens(fd: fd_t, times: *const [2]timespec) c_int; pub extern "c" fn pthread_create(noalias newthread: *pthread_t, noalias attr: ?*const pthread_attr_t, start_routine: extern fn (?*c_void) ?*c_void, noalias arg: ?*c_void) c_int; pub extern "c" fn pthread_attr_init(attr: *pthread_attr_t) c_int; pub extern "c" fn pthread_attr_setstack(attr: *pthread_attr_t, stackaddr: *c_void, stacksize: usize) c_int; +pub extern "c" fn pthread_attr_setguardsize(attr: *pthread_attr_t, guardsize: usize) c_int; pub extern "c" fn pthread_attr_destroy(attr: *pthread_attr_t) c_int; pub extern "c" fn pthread_self() pthread_t; pub extern "c" fn pthread_join(thread: pthread_t, arg_return: ?*?*c_void) c_int; diff --git a/lib/std/thread.zig b/lib/std/thread.zig index f2b27caa97..6abe88c8cf 100644 --- a/lib/std/thread.zig +++ b/lib/std/thread.zig @@ -381,6 +381,11 @@ pub const Thread = struct { mmap_slice.ptr + guard_end_offset, stack_end_offset - guard_end_offset, ) == 0); + // Even though pthread's man pages state that the guard size is + // ignored when the stack address is explicitly given, on some + // plaforms such as NetBSD we still have to zero it to prevent + // random crashes in pthread_join calls + assert(c.pthread_attr_setguardsize(&attr, 0) == 0); const err = c.pthread_create(&thread_ptr.data.handle, &attr, MainFuncs.posixThreadMain, @intToPtr(*c_void, arg)); switch (err) { From 3ccf99c0bd5a681c56c456d1606b5eccfcf31fb7 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Tue, 24 Mar 2020 19:47:18 +0100 Subject: [PATCH 11/11] std: Slim duplicate logic for some calls --- lib/std/c.zig | 1 - lib/std/c/darwin.zig | 1 + lib/std/os.zig | 75 +++++++++++++------------------------------- 3 files changed, 23 insertions(+), 54 deletions(-) diff --git a/lib/std/c.zig b/lib/std/c.zig index 0d8aa13dec..1abad53375 100644 --- a/lib/std/c.zig +++ b/lib/std/c.zig @@ -74,7 +74,6 @@ pub extern "c" fn exit(code: c_int) noreturn; pub extern "c" fn isatty(fd: fd_t) c_int; pub extern "c" fn close(fd: fd_t) c_int; pub extern "c" fn fstat(fd: fd_t, buf: *Stat) c_int; -pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; pub extern "c" fn fstatat(dirfd: fd_t, path: [*:0]const u8, stat_buf: *Stat, flags: u32) c_int; pub extern "c" fn lseek(fd: fd_t, offset: off_t, whence: c_int) off_t; pub extern "c" fn open(path: [*:0]const u8, oflag: c_uint, ...) c_int; diff --git a/lib/std/c/darwin.zig b/lib/std/c/darwin.zig index 2134e0e7a4..74922daa01 100644 --- a/lib/std/c/darwin.zig +++ b/lib/std/c/darwin.zig @@ -13,6 +13,7 @@ pub extern "c" fn _dyld_get_image_vmaddr_slide(image_index: u32) usize; pub extern "c" fn _dyld_get_image_name(image_index: u32) [*:0]const u8; pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: [*]u8, buf_len: usize, basep: *i64) isize; +pub extern "c" fn @"fstat$INODE64"(fd: fd_t, buf: *Stat) c_int; pub extern "c" fn mach_absolute_time() u64; pub extern "c" fn mach_timebase_info(tinfo: ?*mach_timebase_info_data) void; diff --git a/lib/std/os.zig b/lib/std/os.zig index 4e25b254ea..dc032badea 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -2531,29 +2531,15 @@ pub const FStatError = error{ pub fn fstat(fd: fd_t) FStatError!Stat { var stat: Stat = undefined; - if (comptime std.Target.current.isDarwin()) { - switch (darwin.getErrno(darwin.@"fstat$INODE64"(fd, &stat))) { - 0 => return stat, - EINVAL => unreachable, - EBADF => unreachable, // Always a race condition. - ENOMEM => return error.SystemResources, - EACCES => return error.AccessDenied, - else => |err| return unexpectedErrno(err), - } - } - if (std.Target.current.os.tag == .netbsd) { - switch (errno(system.__fstat50(fd, &stat))) { - 0 => return stat, - EINVAL => unreachable, - EBADF => unreachable, // Always a race condition. - ENOMEM => return error.SystemResources, - EACCES => return error.AccessDenied, - else => |err| return unexpectedErrno(err), - } - } + const symbol_name = if (comptime std.Target.current.isDarwin()) + "fstat$INODE64" + else if (std.Target.current.os.tag == .netbsd) + "__fstat50" + else + "fstat"; - switch (errno(system.fstat(fd, &stat))) { + switch (errno(@field(system, symbol_name)(fd, &stat))) { 0 => return stat, EINVAL => unreachable, EBADF => unreachable, // Always a race condition. @@ -3413,16 +3399,12 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { return; } - if (std.Target.current.os.tag == .netbsd) { - switch (errno(system.__clock_gettime50(clk_id, tp))) { - 0 => return, - EFAULT => unreachable, - EINVAL => return error.UnsupportedClock, - else => |err| return unexpectedErrno(err), - } - } + const symbol_name = if (std.Target.current.os.tag == .netbsd) + "__clock_gettime50" + else + "clock_gettime"; - switch (errno(system.clock_gettime(clk_id, tp))) { + switch (errno(@field(system, symbol_name)(clk_id, tp))) { 0 => return, EFAULT => unreachable, EINVAL => return error.UnsupportedClock, @@ -3444,16 +3426,12 @@ pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { return; } - if (std.Target.current.os.tag == .netbsd) { - switch (errno(system.__clock_getres50(clk_id, res))) { - 0 => return, - EFAULT => unreachable, - EINVAL => return error.UnsupportedClock, - else => |err| return unexpectedErrno(err), - } - } + const symbol_name = if (std.Target.current.os.tag == .netbsd) + "__clock_getres50" + else + "clock_getres"; - switch (errno(system.clock_getres(clk_id, res))) { + switch (errno(@field(system, symbol_name)(clk_id, res))) { 0 => return, EFAULT => unreachable, EINVAL => return error.UnsupportedClock, @@ -3519,21 +3497,12 @@ pub const SigaltstackError = error{ } || UnexpectedError; pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { - if (builtin.os.tag == .windows or builtin.os.tag == .uefi or builtin.os.tag == .wasi) - @compileError("std.os.sigaltstack not available for this target"); + const symbol_name = if (std.Target.current.os.tag == .netbsd) + "__sigaltstack14" + else + "sigaltstack"; - if (std.Target.current.os.tag == .netbsd) { - switch (errno(system.__sigaltstack14(ss, old_ss))) { - 0 => return, - EFAULT => unreachable, - EINVAL => unreachable, - ENOMEM => return error.SizeTooSmall, - EPERM => return error.PermissionDenied, - else => |err| return unexpectedErrno(err), - } - } - - switch (errno(system.sigaltstack(ss, old_ss))) { + switch (errno(@field(system, symbol_name)(ss, old_ss))) { 0 => return, EFAULT => unreachable, EINVAL => unreachable,