authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-06 18:35:24-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-06-06 18:35:24-04:00
logbe639eecc209d8039176c9750f28e8c960400fb2
treea8c9d69cc56c0353d90b1b10da9536cc9ce5a2ba
parent920f1dcd2784bf00350843872620f5d64085e267
parent073762395ef3beddf458d87a6b7aad4342b9af8e
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11565 from matu3ba/port_abort

std.os: ported signal handling in abort() from musl

1 files changed, 47 insertions(+), 4 deletions(-)

lib/std/os.zig+47-4
...@@ -442,6 +442,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {...@@ -442,6 +442,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
442/// Causes abnormal process termination.442/// Causes abnormal process termination.
443/// If linking against libc, this calls the abort() libc function. Otherwise443/// If linking against libc, this calls the abort() libc function. Otherwise
444/// it raises SIGABRT followed by SIGKILL and finally lo444/// it raises SIGABRT followed by SIGKILL and finally lo
445/// Invokes the current signal handler for SIGABRT, if any.
445pub fn abort() noreturn {446pub fn abort() noreturn {
446 @setCold(true);447 @setCold(true);
447 // MSVCRT abort() sometimes opens a popup window which is undesirable, so448 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
...@@ -454,12 +455,44 @@ pub fn abort() noreturn {...@@ -454,12 +455,44 @@ pub fn abort() noreturn {
454 windows.kernel32.ExitProcess(3);455 windows.kernel32.ExitProcess(3);
455 }456 }
456 if (!builtin.link_libc and builtin.os.tag == .linux) {457 if (!builtin.link_libc and builtin.os.tag == .linux) {
458 // The Linux man page says that the libc abort() function
459 // "first unblocks the SIGABRT signal", but this is a footgun
460 // for user-defined signal handlers that want to restore some state in
461 // some program sections and crash in others.
462 // So, the user-installed SIGABRT handler is run, if present.
457 raise(SIG.ABRT) catch {};463 raise(SIG.ABRT) catch {};
458464
459 // TODO the rest of the implementation of abort() from musl libc here465 // Disable all signal handlers.
466 sigprocmask(SIG.BLOCK, &linux.all_mask, null);
460467
468 // Only one thread may proceed to the rest of abort().
469 if (!builtin.single_threaded) {
470 const global = struct {
471 var abort_entered: bool = false;
472 };
473 while (@cmpxchgWeak(bool, &global.abort_entered, false, true, .SeqCst, .SeqCst)) |_| {}
474 }
475
476 // Install default handler so that the tkill below will terminate.
477 const sigact = Sigaction{
478 .handler = .{ .sigaction = SIG.DFL },
479 .mask = undefined,
480 .flags = undefined,
481 .restorer = undefined,
482 };
483 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
484 error.OperationNotSupported => unreachable,
485 };
486
487 _ = linux.tkill(linux.gettid(), SIG.ABRT);
488
489 const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)};
490 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
491
492 // Beyond this point should be unreachable.
493 @intToPtr(*allowzero volatile u8, 0).* = 0;
461 raise(SIG.KILL) catch {};494 raise(SIG.KILL) catch {};
462 exit(127);495 exit(127); // Pid 1 might not be signalled in some containers.
463 }496 }
464 if (builtin.os.tag == .uefi) {497 if (builtin.os.tag == .uefi) {
465 exit(0); // TODO choose appropriate exit code498 exit(0); // TODO choose appropriate exit code
...@@ -485,13 +518,13 @@ pub fn raise(sig: u8) RaiseError!void {...@@ -485,13 +518,13 @@ pub fn raise(sig: u8) RaiseError!void {
485 if (builtin.os.tag == .linux) {518 if (builtin.os.tag == .linux) {
486 var set: sigset_t = undefined;519 var set: sigset_t = undefined;
487 // block application signals520 // block application signals
488 _ = linux.sigprocmask(SIG.BLOCK, &linux.app_mask, &set);521 sigprocmask(SIG.BLOCK, &linux.app_mask, &set);
489522
490 const tid = linux.gettid();523 const tid = linux.gettid();
491 const rc = linux.tkill(tid, sig);524 const rc = linux.tkill(tid, sig);
492525
493 // restore signal mask526 // restore signal mask
494 _ = linux.sigprocmask(SIG.SETMASK, &set, null);527 sigprocmask(SIG.SETMASK, &set, null);
495528
496 switch (errno(rc)) {529 switch (errno(rc)) {
497 .SUCCESS => return,530 .SUCCESS => return,
...@@ -5441,6 +5474,16 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -5441,6 +5474,16 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
5441 }5474 }
5442}5475}
54435476
5477/// Sets the thread signal mask.
5478pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*sigset_t) void {
5479 switch (errno(system.sigprocmask(flags, set, oldset))) {
5480 .SUCCESS => return,
5481 .FAULT => unreachable,
5482 .INVAL => unreachable,
5483 else => unreachable,
5484 }
5485}
5486
5444pub const FutimensError = error{5487pub const FutimensError = error{
5445 /// times is NULL, or both tv_nsec values are UTIME_NOW, and either:5488 /// times is NULL, or both tv_nsec values are UTIME_NOW, and either:
5446 /// * the effective user ID of the caller does not match the owner5489 /// * the effective user ID of the caller does not match the owner