diff --git a/std/c/darwin.zig b/std/c/darwin.zig index 156429e7b..14a5baff5 100644 --- a/std/c/darwin.zig +++ b/std/c/darwin.zig @@ -54,3 +54,5 @@ pub extern "c" fn mach_port_deallocate(task: ipc_space_t, name: mach_port_name_t pub fn sigaddset(set: *sigset_t, signo: u5) void { set.* |= u32(1) << (signo - 1); } + +pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; diff --git a/std/c/freebsd.zig b/std/c/freebsd.zig index 70f3aeb9c..eaa073677 100644 --- a/std/c/freebsd.zig +++ b/std/c/freebsd.zig @@ -1,4 +1,8 @@ +const std = @import("../std.zig"); +use std.c; + extern "c" fn __error() *c_int; pub const _errno = __error; 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; diff --git a/std/c/linux.zig b/std/c/linux.zig index 83c6bdfe5..50c4b185d 100644 --- a/std/c/linux.zig +++ b/std/c/linux.zig @@ -25,3 +25,5 @@ pub extern "c" fn getauxval(__type: c_ulong) c_ulong; 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 sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; diff --git a/std/c/netbsd.zig b/std/c/netbsd.zig index c677e1500..0ee94e822 100644 --- a/std/c/netbsd.zig +++ b/std/c/netbsd.zig @@ -1,4 +1,8 @@ +const std = @import("../std.zig"); +use 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; diff --git a/std/os.zig b/std/os.zig index 631cc266a..ee476258a 100644 --- a/std/os.zig +++ b/std/os.zig @@ -2442,6 +2442,29 @@ pub fn unexpectedErrno(err: usize) UnexpectedError { return error.Unexpected; } +pub const SigaltstackError = error{ + /// The supplied stack size was less than MINSIGSTKSZ. + SizeTooSmall, + + /// Attempted to change the signal stack while it was active. + PermissionDenied, + Unexpected, +}; + +pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) SigaltstackError!void { + if (windows.is_the_target or uefi.is_the_target or wasi.is_the_target) + @compileError("std.os.sigaltstack not available for this target"); + + switch (errno(system.sigaltstack(ss, old_ss))) { + 0 => return, + EFAULT => unreachable, + EINVAL => unreachable, + ENOMEM => return error.SizeTooSmall, + EPERM => return error.PermissionDenied, + else => |err| return unexpectedErrno(err), + } +} + test "" { _ = @import("os/darwin.zig"); _ = @import("os/freebsd.zig"); diff --git a/std/os/bits/darwin.zig b/std/os/bits/darwin.zig index a685735da..39dae6e7a 100644 --- a/std/os/bits/darwin.zig +++ b/std/os/bits/darwin.zig @@ -1078,3 +1078,15 @@ pub const EQFULL = 106; /// Must be equal largest errno pub const ELAST = 106; + +pub const SIGSTKSZ = 131072; +pub const MINSIGSTKSZ = 32768; + +pub const SS_ONSTACK = 1; +pub const SS_DISABLE = 4; + +pub const stack_t = extern struct { + ss_sp: [*]u8, + ss_size: isize, + ss_flags: i32, +}; diff --git a/std/os/bits/freebsd.zig b/std/os/bits/freebsd.zig index 1925b75f3..3fc019f9c 100644 --- a/std/os/bits/freebsd.zig +++ b/std/os/bits/freebsd.zig @@ -835,3 +835,19 @@ pub const ENOTRECOVERABLE = 95; // State not recoverable pub const EOWNERDEAD = 96; // Previous owner died pub const ELAST = 96; // Must be equal largest errno + +pub const MINSIGSTKSZ = switch (builtin.arch) { + .i386, .x86_64 => 2048, + .arm, .aarch64 => 4096, + else => @compileError("MINSIGSTKSZ not defined for this architecture"), +}; +pub const SIGSTKSZ = MINSIGSTKSZ + 32768; + +pub const SS_ONSTACK = 1; +pub const SS_DISABLE = 4; + +pub const stack_t = extern struct { + ss_sp: [*]u8, + ss_size: isize, + ss_flags: i32, +}; diff --git a/std/os/bits/linux.zig b/std/os/bits/linux.zig index 44e713b15..4a1734a14 100644 --- a/std/os/bits/linux.zig +++ b/std/os/bits/linux.zig @@ -929,3 +929,24 @@ pub fn CPU_COUNT(set: cpu_set_t) cpu_count_t { //#define CPU_COUNT(set) CPU_COUNT_S(sizeof(cpu_set_t),set) //#define CPU_ZERO(set) CPU_ZERO_S(sizeof(cpu_set_t),set) //#define CPU_EQUAL(s1,s2) CPU_EQUAL_S(sizeof(cpu_set_t),s1,s2) + +pub const MINSIGSTKSZ = switch (builtin.arch) { + .i386, .x86_64, .arm => 2048, + .aarch64 => 5120, + else => @compileError("MINSIGSTKSZ not defined for this architecture"), +}; +pub const SIGSTKSZ = switch (builtin.arch) { + .i386, .x86_64, .arm => 8192, + .aarch64 => 16384, + else => @compileError("SIGSTKSZ not defined for this architecture"), +}; + +pub const SS_ONSTACK = 1; +pub const SS_DISABLE = 2; +pub const SS_AUTODISARM = 1 << 31; + +pub const stack_t = extern struct { + ss_sp: [*]u8, + ss_flags: i32, + ss_size: isize, +}; diff --git a/std/os/bits/netbsd.zig b/std/os/bits/netbsd.zig index fc4c2904e..e7a0f6ea5 100644 --- a/std/os/bits/netbsd.zig +++ b/std/os/bits/netbsd.zig @@ -723,3 +723,15 @@ pub const ENOLINK = 95; // Link has been severed pub const EPROTO = 96; // Protocol error pub const ELAST = 96; // Must equal largest errno + +pub const MINSIGSTKSZ = 8192; +pub const SIGSTKSZ = MINSIGSTKSZ + 32768; + +pub const SS_ONSTACK = 1; +pub const SS_DISABLE = 4; + +pub const stack_t = extern struct { + ss_sp: [*]u8, + ss_size: isize, + ss_flags: i32, +}; diff --git a/std/os/linux.zig b/std/os/linux.zig index 5d2644668..aee34b10a 100644 --- a/std/os/linux.zig +++ b/std/os/linux.zig @@ -818,6 +818,10 @@ pub fn capset(hdrp: *cap_user_header_t, datap: *const cap_user_data_t) usize { return syscall2(SYS_capset, @ptrToInt(hdrp), @ptrToInt(datap)); } +pub fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) usize { + return syscall2(SYS_sigaltstack, @ptrToInt(ss), @ptrToInt(old_ss)); +} + // XXX: This should be weak extern const __ehdr_start: elf.Ehdr = undefined; diff --git a/std/os/test.zig b/std/os/test.zig index d4d662e97..dfcd25c4b 100644 --- a/std/os/test.zig +++ b/std/os/test.zig @@ -149,3 +149,14 @@ test "realpath" { var buf: [std.fs.MAX_PATH_BYTES]u8 = undefined; testing.expectError(error.FileNotFound, fs.realpath("definitely_bogus_does_not_exist1234", &buf)); } + +test "sigaltstack" { + if (builtin.os == .windows or builtin.os == .wasi) return error.SkipZigTest; + + var st: os.stack_t = undefined; + try os.sigaltstack(null, &st); + // Setting a stack size less than MINSIGSTKSZ returns ENOMEM + st.ss_flags = 0; + st.ss_size = 1; + testing.expectError(error.SizeTooSmall, os.sigaltstack(&st, null)); +} diff --git a/std/os/uefi.zig b/std/os/uefi.zig index 8ed60d9c9..7102938d7 100644 --- a/std/os/uefi.zig +++ b/std/os/uefi.zig @@ -1,2 +1,6 @@ // TODO this is where the extern declarations go. For example, see // inc/efilib.h in gnu-efi-code + +const builtin = @import("builtin"); + +pub const is_the_target = builtin.os == .uefi;