authorgravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2023-02-18 11:46:24-07:00
committergravatar for johnnymarler@gmail.comJonathan Marler <johnnymarler@gmail.com> 2023-02-18 11:49:15-07:00
logdafefe9c9d3ffd484915ead0474c7e772f1dfcfb
treefc8d6b6144f52645b7d3bf0f4796ae6326ab9327
parent0a8fe34b11f7a44fd7f744bf4332353a5e7bfcdf

use std_options for keep_sigpipe and existence of SIG.PIPE to check for support


3 files changed, 19 insertions(+), 33 deletions(-)

lib/std/os.zig+2-32
...@@ -7057,42 +7057,12 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {...@@ -7057,42 +7057,12 @@ pub fn timerfd_gettime(fd: i32) TimerFdGetError!linux.itimerspec {
7057 };7057 };
7058}7058}
70597059
7060/// Whether or not the current target support SIGPIPE7060pub const have_sigpipe_support = @hasDecl(@This(), "SIG") and @hasDecl(SIG, "PIPE");
7061pub const have_sigpipe_support = switch (builtin.os.tag) {
7062 .linux,
7063 .macos,
7064 .netbsd,
7065 .solaris,
7066 .freebsd,
7067 .openbsd,
7068 => true,
7069 else => false,
7070};
7071
7072pub const keep_sigpipe: bool = if (@hasDecl(root, "keep_sigpipe"))
7073 root.keep_sigpipe
7074else
7075 false;
70767061
7077fn noopSigHandler(_: c_int) callconv(.C) void {}7062fn noopSigHandler(_: c_int) callconv(.C) void {}
70787063
7079/// This function will tell the kernel to ignore SIGPIPE rather than terminate
7080/// the process. This function is automatically called in `start.zig` before
7081/// `main`. This behavior can be disabled by adding this to your root module:
7082///
7083/// pub const keep_sigpipe = true;
7084///
7085/// SIGPIPE is triggered when a process attempts to write to a broken pipe.
7086/// By default, SIGPIPE will terminate the process without giving the program
7087/// an opportunity to handle the situation. Unlike a segfault, it doesn't
7088/// trigger the panic handler so all the developer sees is that the program
7089/// terminated with no indication as to why.
7090///
7091/// By telling the kernel to instead ignore SIGPIPE, writes to broken pipes
7092/// will return the EPIPE error (error.BrokenPipe) and the program can handle
7093/// it like any other error.
7094pub fn maybeIgnoreSigpipe() void {7064pub fn maybeIgnoreSigpipe() void {
7095 if (have_sigpipe_support and !keep_sigpipe) {7065 if (have_sigpipe_support and !std.options.keep_sigpipe) {
7096 const act = Sigaction{7066 const act = Sigaction{
7097 // We set handler to a noop function instead of SIG.IGN so we don't leak our7067 // We set handler to a noop function instead of SIG.IGN so we don't leak our
7098 // signal disposition to a child process7068 // signal disposition to a child process
lib/std/std.zig+16
...@@ -167,6 +167,22 @@ pub const options = struct {...@@ -167,6 +167,22 @@ pub const options = struct {
167 options_override.crypto_always_getrandom167 options_override.crypto_always_getrandom
168 else168 else
169 false;169 false;
170
171 /// By default Zig disables SIGPIPE by setting a "no-op" handler for it. Set this option
172 /// to `true` to prevent that.
173 ///
174 /// Note that we use a "no-op" handler instead of SIG_IGN because it will not be inherited by
175 /// any child process.
176 ///
177 /// SIGPIPE is triggered when a process attempts to write to a broken pipe. By default, SIGPIPE
178 /// will terminate the process instead of exiting. It doesn't trigger the panic handler so in many
179 /// cases it's unclear why the process was terminated. By capturing SIGPIPE instead, functions that
180 /// write to broken pipes will return the EPIPE error (error.BrokenPipe) and the program can handle
181 /// it like any other error.
182 pub const keep_sigpipe: bool = if (@hasDecl(options_override, "keep_sigpipe"))
183 options_override.keep_sigpipe
184 else
185 false;
170};186};
171187
172// This forces the start.zig file to be imported, and the comptime logic inside that188// This forces the start.zig file to be imported, and the comptime logic inside that
test/standalone/sigpipe/breakpipe.zig+1-1
...@@ -1,7 +1,7 @@...@@ -1,7 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const build_options = @import("build_options");2const build_options = @import("build_options");
33
4pub usingnamespace if (build_options.keep_sigpipe) struct {4pub const std_options = if (build_options.keep_sigpipe) struct {
5 pub const keep_sigpipe = true;5 pub const keep_sigpipe = true;
6} else struct {6} else struct {
7 // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false7 // intentionally not setting keep_sigpipe to ensure the default behavior is equivalent to false