authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-06 15:29:34-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-06 15:34:20-07:00
log073762395ef3beddf458d87a6b7aad4342b9af8e
treecd0d35dfc53bb6ac67d6a1c39123ad0486a05b79
parentd1e8b73939ae9f139d90157a4623c5fe68b0ae64

std.os.abort patch cleanups

* move global into function scope * clarify comments * avoid unnecessary usage of std.atomic API * switch on error instead of `catch unreachable` * call linux.gettid() instead of going through higher level API and doing unnecessary casting

1 files changed, 22 insertions(+), 37 deletions(-)

lib/std/os.zig+22-37
...@@ -250,15 +250,6 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin....@@ -250,15 +250,6 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin.
250 else => undefined,250 else => undefined,
251};251};
252252
253/// Atomic to guard correct program teardown in abort()
254var abort_entered = impl: {
255 if (builtin.single_threaded) {
256 break :impl {};
257 } else {
258 break :impl std.atomic.Atomic(bool).init(false);
259 }
260};
261
262/// To obtain errno, call this function with the return value of the253/// To obtain errno, call this function with the return value of the
263/// system function call. For some systems this will obtain the value directly254/// system function call. For some systems this will obtain the value directly
264/// from the return code; for others it will use a thread-local errno variable.255/// from the return code; for others it will use a thread-local errno variable.
...@@ -451,7 +442,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {...@@ -451,7 +442,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void {
451/// Causes abnormal process termination.442/// Causes abnormal process termination.
452/// If linking against libc, this calls the abort() libc function. Otherwise443/// If linking against libc, this calls the abort() libc function. Otherwise
453/// it raises SIGABRT followed by SIGKILL and finally lo444/// it raises SIGABRT followed by SIGKILL and finally lo
454/// assume: Current signal handler for SIGABRT does **not call abort**.445/// Invokes the current signal handler for SIGABRT, if any.
455pub fn abort() noreturn {446pub fn abort() noreturn {
456 @setCold(true);447 @setCold(true);
457 // MSVCRT abort() sometimes opens a popup window which is undesirable, so448 // MSVCRT abort() sometimes opens a popup window which is undesirable, so
...@@ -464,49 +455,44 @@ pub fn abort() noreturn {...@@ -464,49 +455,44 @@ pub fn abort() noreturn {
464 windows.kernel32.ExitProcess(3);455 windows.kernel32.ExitProcess(3);
465 }456 }
466 if (!builtin.link_libc and builtin.os.tag == .linux) {457 if (!builtin.link_libc and builtin.os.tag == .linux) {
467 // Linux man page wants to first "unblock SIG.ABRT", but this is a footgun458 // The Linux man page says that the libc abort() function
459 // "first unblocks the SIGABRT signal", but this is a footgun
468 // for user-defined signal handlers that want to restore some state in460 // for user-defined signal handlers that want to restore some state in
469 // some program sections and crash in others461 // some program sections and crash in others.
470462 // So, the user-installed SIGABRT handler is run, if present.
471 // user installed SIGABRT handler is run, if installed
472 raise(SIG.ABRT) catch {};463 raise(SIG.ABRT) catch {};
473464
474 // disable all signal handlers465 // Disable all signal handlers.
475 sigprocmask(SIG.BLOCK, &linux.all_mask, null);466 sigprocmask(SIG.BLOCK, &linux.all_mask, null);
476467
477 // ensure teardown by one thread468 // Only one thread may proceed to the rest of abort().
478 if (!builtin.single_threaded) {469 if (!builtin.single_threaded) {
479 while (abort_entered.compareAndSwap(false, true, .SeqCst, .SeqCst)) |_| {}470 const global = struct {
471 var abort_entered: bool = false;
472 };
473 while (@cmpxchgWeak(bool, &global.abort_entered, false, true, .SeqCst, .SeqCst)) |_| {}
480 }474 }
481475
482 // install default handler to terminate476 // Install default handler so that the tkill below will terminate.
483 const sigact = Sigaction{477 const sigact = Sigaction{
484 .handler = .{ .sigaction = SIG.DFL },478 .handler = .{ .sigaction = SIG.DFL },
485 .mask = undefined,479 .mask = undefined,
486 .flags = undefined,480 .flags = undefined,
487 .restorer = undefined,481 .restorer = undefined,
488 };482 };
489 sigaction(SIG.ABRT, &sigact, null) catch unreachable;483 sigaction(SIG.ABRT, &sigact, null) catch |err| switch (err) {
484 error.OperationNotSupported => unreachable,
485 };
490486
491 // make sure we have a pending SIGABRT queued487 _ = linux.tkill(linux.gettid(), SIG.ABRT);
492 const tid = std.Thread.getCurrentId();
493 _ = linux.tkill(@intCast(i32, tid), SIG.ABRT);
494488
495 // SIG.ABRT signal will run default handler
496 const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)};489 const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)};
497 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null); // [32]u32490 sigprocmask(SIG.UNBLOCK, &sigabrtmask, null);
498
499 // Beyond this point should be unreachable
500
501 // abnormal termination without using signal handler
502 const nullptr: *allowzero volatile u8 = @intToPtr(*allowzero volatile u8, 0);
503 nullptr.* = 0;
504491
505 // try SIGKILL, which is no abnormal termination as defined by POSIX and ISO C492 // Beyond this point should be unreachable.
493 @intToPtr(*allowzero volatile u8, 0).* = 0;
506 raise(SIG.KILL) catch {};494 raise(SIG.KILL) catch {};
507495 exit(127); // Pid 1 might not be signalled in some containers.
508 // pid 1 might not be signalled in some containers
509 exit(127);
510 }496 }
511 if (builtin.os.tag == .uefi) {497 if (builtin.os.tag == .uefi) {
512 exit(0); // TODO choose appropriate exit code498 exit(0); // TODO choose appropriate exit code
...@@ -5488,13 +5474,12 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -5488,13 +5474,12 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
5488 }5474 }
5489}5475}
54905476
5491/// Set the thread signal mask5477/// Sets the thread signal mask.
5492/// Invalid masks are checked in Debug and ReleaseFast
5493pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*sigset_t) void {5478pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*sigset_t) void {
5494 switch (errno(system.sigprocmask(flags, set, oldset))) {5479 switch (errno(system.sigprocmask(flags, set, oldset))) {
5495 .SUCCESS => return,5480 .SUCCESS => return,
5496 .FAULT => unreachable,5481 .FAULT => unreachable,
5497 .INVAL => unreachable, // main purpose: debug InvalidValue error5482 .INVAL => unreachable,
5498 else => unreachable,5483 else => unreachable,
5499 }5484 }
5500}5485}