-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Add sigaltstack syscall for Linux #2546
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
std/os/linux.zig
Outdated
pub const MINSIGSTKSZ = switch (builtin.arch) { | ||
.i386, .x86_64, .arm => 2048, | ||
.aarch64 => 6144, | ||
else => @compileError("MINSIGSTKSZ not defined for this architecture"), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this make things fail on all non-listed architectures?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also we can grab all the values from the kernel, this search is useful: https://elixir.bootlin.com/linux/latest/ident/MINSIGSTKSZ
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that so far all the per-arch things are in their own files (see e.g. linux/arm64.zig)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Doesn't this make things fail on all non-listed architectures?
Yes? IMO it's better to be explicit about missing definitions.
Also we can grab all the values from the kernel, this search is useful
That's not so easy, sometimes different libcs muddle the waters by changing that value. E.g. The aarch64 value is greater than the kernel-reported one. This begs another question, do we want to stay true to the kernel or try to paper over the kernel+libc differences?
Note that so far all the per-arch things are in their own files (see e.g. linux/arm64.zig)
See point 1, pub use
masks the missing definitions unless you actually try to use it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
E.g. The aarch64 value is greater than the kernel-reported one
Is it? I thought it was only ia64 that was weird https://elixir.bootlin.com/linux/latest/source/arch/ia64/include/uapi/asm/signal.h#L95
do we want to stay true to the kernel or try to paper over the kernel+libc differences?
Usually I'd say "stay true to the kernel", but for the specific case of a "minimum space required", I'd take the larger of the two options (which in the case of ia64, is userspace)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting. Is this because libc reserves some stack space in signal handling for itself?
If that's the case, inline with my comment here, std/os/linux.zig
should have the kernel definition, std/c/linux.zig
should have the libc definition.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this because libc reserves some stack space in signal handling for itself?
Here's the rationale:
since the default (SIGSTKSZ) has always been 6k larger than the minimum, it is also increased to maintain the 6k usable by the signal handler. this happens to be able to store one pathname buffer and should be sufficient for calling any function in libc that doesn't involve conversion between floating point and decimal representations.
Any number is fine as long as you're able to satisfy the requirements imposed by the kernel.
I'm also interested in hearing your ideas on how to define this in c.zig
, should stack_t
be redefined there? Should it reference the definition in linux.zig
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the rationale:
So sounds like libc just adds some extra space "just in case": I would go with the kernel definition.
Though I could maybe be convinced to add a separate definition to std/c/linux.zig
so that calling C libraries that assume enough space for a pathname buffer don't fail.
I'm also interested in hearing your ideas on how to define this in
c.zig
, shouldstack_t
be redefined there? Should it reference the definition inlinux.zig
?
Unless the stack_t
definition in std/c/linux.zig
(note that it would not be in std/c.zig
) needed to be something different to what the kernel provides, it would reference the definition in std/os/linux.zig
.
i.e. stack_t
would fall under the condition I outlined of:
If libc defines a function that e.g. "takes a pointer to a native
struct sockaddr
" then you may use type definitions fromstd/os/*
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So sounds like libc just adds some extra space "just in case": I would go with the kernel definition.
The kernel prescribes the minimum amount of stack you need for an empty handler to execute, if you want to do anything remotely useful you need more space than that.
I agree on picking the kernel definition here, let's report the bare minimum and then have the user pick a good value.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep. The user should really be using the kernel minimum plus @stack_size(their_handler)
(see #157 )
std/os/linux.zig
Outdated
}; | ||
|
||
pub const stack_t = extern struct { | ||
ss_sp: usize, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a [*]u8
or a *c_void
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should this be a [*]u8 or a *c_void?
It's a matter of picking the poison you like the most, you either need a @pointerToInt
or a @ptrCast
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
With a pointer type you can't accidentally pass a number. Also pointers have additional properties such as alignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh well, some more type-safety is always welcome. I'll turn this into a *c_void for symmetry with the other structure definitions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
a couple things and then I think this is ready to merge. thanks daurnimator for the review comments
@@ -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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
these can go in std/c.zig
yeah? they're the same on every platform
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They are, but they're not supported by every platform and that's why they've been duplicated.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I suppose that's better than a link error if accidentally used. Makes sense to me.
std/os/linux/test.zig
Outdated
@@ -83,3 +83,12 @@ test "dl_iterate_phdr" { | |||
expect(linux.dl_iterate_phdr(usize, iter_fn, &counter) != 0); | |||
expect(counter != 0); | |||
} | |||
|
|||
test "sigaltstack" { | |||
var st: linux.stack_t = undefined; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add the wrapper function in std.os? Then this test can go into std/os/test.zig and test all most OS's including libc-linked builds. probably would have to be disabled for windows and wasi.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you add the wrapper function in std.os
I thought that was only for abstractions that were valid across all the OSs.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's a candidate for os.zig if:
- it's available on more than 1 os (or available on libc and non libc for linux), or
- it would be worthwhile to have zig-friendly function signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I found the cause of the test failures
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; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wow I didn't catch this the first time.
pub extern "c" fn sigaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; | |
pub extern "c" fn signaltstack(ss: ?*stack_t, old_ss: ?*stack_t) c_int; |
(the other ones too)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, my mistake. I saw /home/vsts/work/1/s/std/os.zig:2458:25: error: container 'c' has no member called 'sigaltstack'
and made an incorrect assumption.
So this looks like a bug with use
then? damn
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this looks like a bug with
use
then? damn
ah right of course. it was just the same darwin bug on all 3 of the CI because they each test cross compilation.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So this looks like a bug with use then? damn
Nope, I just forgot to add the declaration in darwin.zig
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well I feel silly. sorry for all the noise
|
||
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"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this if and explicit compile error is just fine, but not required. everywhere else just lets the natural compile error happen if you call the function on an unsupported target.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Explicit is better than implicit, I believe that goes for error messages too.
@@ -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" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's misspelled here too and below oops. my mistake
std/os/test.zig
Outdated
@@ -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 and builtin.os != .uefi and builtin.os != .wasi) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is fine. note you can also do this:
if (builtin.os == .windows or builtin.os == .uefi or builtin.os == .wasi) return error.SkipZigTest;
also this test isn't run for uefi so you don't need that check.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, that looks better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ready to merge as soon as the tests pass
#2380 is probably relevant here, this function is available on all the posix-compatible OS but we have to re-define it every time.
Also there's no
c.zig
implementation as I didn't know ifstack_t
had to be re-defined there or whatever.The standard library has become way too tangled...