| ... | @@ -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 | }; |
| 252 | | 252 | |
| 253 | /// Atomic to guard correct program teardown in abort() | | |
| 254 | var 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 the | 253 | /// To obtain errno, call this function with the return value of the |
| 263 | /// system function call. For some systems this will obtain the value directly | 254 | /// 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. Otherwise | 443 | /// If linking against libc, this calls the abort() libc function. Otherwise |
| 453 | /// it raises SIGABRT followed by SIGKILL and finally lo | 444 | /// 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. |
| 455 | pub fn abort() noreturn { | 446 | pub fn abort() noreturn { |
| 456 | @setCold(true); | 447 | @setCold(true); |
| 457 | // MSVCRT abort() sometimes opens a popup window which is undesirable, so | 448 | // 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 footgun | 458 | // 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 in | 460 | // for user-defined signal handlers that want to restore some state in |
| 469 | // some program sections and crash in others | 461 | // some program sections and crash in others. |
| 470 | | 462 | // 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 {}; |
| 473 | | 464 | |
| 474 | // disable all signal handlers | 465 | // Disable all signal handlers. |
| 475 | sigprocmask(SIG.BLOCK, &linux.all_mask, null); | 466 | sigprocmask(SIG.BLOCK, &linux.all_mask, null); |
| 476 | | 467 | |
| 477 | // ensure teardown by one thread | 468 | // 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 | } |
| 481 | | 475 | |
| 482 | // install default handler to terminate | 476 | // 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 | }; |
| 490 | | 486 | |
| 491 | // make sure we have a pending SIGABRT queued | 487 | _ = linux.tkill(linux.gettid(), SIG.ABRT); |
| 492 | const tid = std.Thread.getCurrentId(); | | |
| 493 | _ = linux.tkill(@intCast(i32, tid), SIG.ABRT); | | |
| 494 | | 488 | |
| 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]u32 | 490 | 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; | | |
| 504 | | 491 | |
| 505 | // try SIGKILL, which is no abnormal termination as defined by POSIX and ISO C | 492 | // Beyond this point should be unreachable. |
| | 493 | @intToPtr(*allowzero volatile u8, 0).* = 0; |
| 506 | raise(SIG.KILL) catch {}; | 494 | raise(SIG.KILL) catch {}; |
| 507 | | 495 | 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 code | 498 | 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 | } |
| 5490 | | 5476 | |
| 5491 | /// Set the thread signal mask | 5477 | /// Sets the thread signal mask. |
| 5492 | /// Invalid masks are checked in Debug and ReleaseFast | | |
| 5493 | pub fn sigprocmask(flags: u32, noalias set: ?*const sigset_t, noalias oldset: ?*sigset_t) void { | 5478 | pub 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 error | 5482 | .INVAL => unreachable, |
| 5498 | else => unreachable, | 5483 | else => unreachable, |
| 5499 | } | 5484 | } |
| 5500 | } | 5485 | } |