| ... | @@ -250,6 +250,15 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin. | ... | @@ -250,6 +250,15 @@ 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 | |
| 253 | /// To obtain errno, call this function with the return value of the | 262 | /// To obtain errno, call this function with the return value of the |
| 254 | /// system function call. For some systems this will obtain the value directly | 263 | /// system function call. For some systems this will obtain the value directly |
| 255 | /// from the return code; for others it will use a thread-local errno variable. | 264 | /// from the return code; for others it will use a thread-local errno variable. |
| ... | @@ -442,6 +451,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void { | ... | @@ -442,6 +451,7 @@ fn getRandomBytesDevURandom(buf: []u8) !void { |
| 442 | /// Causes abnormal process termination. | 451 | /// Causes abnormal process termination. |
| 443 | /// If linking against libc, this calls the abort() libc function. Otherwise | 452 | /// If linking against libc, this calls the abort() libc function. Otherwise |
| 444 | /// it raises SIGABRT followed by SIGKILL and finally lo | 453 | /// it raises SIGABRT followed by SIGKILL and finally lo |
| | 454 | /// assume: Current signal handler for SIGABRT does **not call abort**. |
| 445 | pub fn abort() noreturn { | 455 | pub fn abort() noreturn { |
| 446 | @setCold(true); | 456 | @setCold(true); |
| 447 | // MSVCRT abort() sometimes opens a popup window which is undesirable, so | 457 | // MSVCRT abort() sometimes opens a popup window which is undesirable, so |
| ... | @@ -454,11 +464,48 @@ pub fn abort() noreturn { | ... | @@ -454,11 +464,48 @@ pub fn abort() noreturn { |
| 454 | windows.kernel32.ExitProcess(3); | 464 | windows.kernel32.ExitProcess(3); |
| 455 | } | 465 | } |
| 456 | if (!builtin.link_libc and builtin.os.tag == .linux) { | 466 | if (!builtin.link_libc and builtin.os.tag == .linux) { |
| | 467 | // Linux man page wants to first "unblock SIG.ABRT", but this is a footgun |
| | 468 | // for user-defined signal handlers that want to restore some state in |
| | 469 | // some program sections and crash in others |
| | 470 | |
| | 471 | // user installed SIGABRT handler is run, if installed |
| 457 | raise(SIG.ABRT) catch {}; | 472 | raise(SIG.ABRT) catch {}; |
| 458 | | 473 | |
| 459 | // TODO the rest of the implementation of abort() from musl libc here | 474 | // disable all signal handlers |
| | 475 | sigprocmask(SIG.BLOCK, &linux.all_mask, null); |
| | 476 | |
| | 477 | // ensure teardown by one thread |
| | 478 | if (!builtin.single_threaded) { |
| | 479 | while (abort_entered.compareAndSwap(false, true, .SeqCst, .SeqCst)) |_| {} |
| | 480 | } |
| | 481 | |
| | 482 | // install default handler to terminate |
| | 483 | const sigact = Sigaction{ |
| | 484 | .handler = .{ .sigaction = SIG.DFL }, |
| | 485 | .mask = undefined, |
| | 486 | .flags = undefined, |
| | 487 | .restorer = undefined, |
| | 488 | }; |
| | 489 | sigaction(SIG.ABRT, &sigact, null) catch unreachable; |
| | 490 | |
| | 491 | // make sure we have a pending SIGABRT queued |
| | 492 | const tid = std.Thread.getCurrentId(); |
| | 493 | _ = linux.tkill(@intCast(i32, tid), SIG.ABRT); |
| 460 | | 494 | |
| | 495 | // SIG.ABRT signal will run default handler |
| | 496 | const sigabrtmask: linux.sigset_t = [_]u32{0} ** 31 ++ [_]u32{1 << (SIG.ABRT - 1)}; |
| | 497 | sigprocmask(SIG.UNBLOCK, &sigabrtmask, null); // [32]u32 |
| | 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 | |
| | 505 | // try SIGKILL, which is no abnormal termination as defined by POSIX and ISO C |
| 461 | raise(SIG.KILL) catch {}; | 506 | raise(SIG.KILL) catch {}; |
| | 507 | |
| | 508 | // pid 1 might not be signalled in some containers |
| 462 | exit(127); | 509 | exit(127); |
| 463 | } | 510 | } |
| 464 | if (builtin.os.tag == .uefi) { | 511 | if (builtin.os.tag == .uefi) { |
| ... | @@ -485,13 +532,13 @@ pub fn raise(sig: u8) RaiseError!void { | ... | @@ -485,13 +532,13 @@ pub fn raise(sig: u8) RaiseError!void { |
| 485 | if (builtin.os.tag == .linux) { | 532 | if (builtin.os.tag == .linux) { |
| 486 | var set: sigset_t = undefined; | 533 | var set: sigset_t = undefined; |
| 487 | // block application signals | 534 | // block application signals |
| 488 | _ = linux.sigprocmask(SIG.BLOCK, &linux.app_mask, &set); | 535 | sigprocmask(SIG.BLOCK, &linux.app_mask, &set); |
| 489 | | 536 | |
| 490 | const tid = linux.gettid(); | 537 | const tid = linux.gettid(); |
| 491 | const rc = linux.tkill(tid, sig); | 538 | const rc = linux.tkill(tid, sig); |
| 492 | | 539 | |
| 493 | // restore signal mask | 540 | // restore signal mask |
| 494 | _ = linux.sigprocmask(SIG.SETMASK, &set, null); | 541 | sigprocmask(SIG.SETMASK, &set, null); |
| 495 | | 542 | |
| 496 | switch (errno(rc)) { | 543 | switch (errno(rc)) { |
| 497 | .SUCCESS => return, | 544 | .SUCCESS => return, |
| ... | @@ -5441,6 +5488,17 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact | ... | @@ -5441,6 +5488,17 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact |
| 5441 | } | 5488 | } |
| 5442 | } | 5489 | } |
| 5443 | | 5490 | |
| | 5491 | /// Set 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 { |
| | 5494 | switch (errno(system.sigprocmask(flags, set, oldset))) { |
| | 5495 | .SUCCESS => return, |
| | 5496 | .FAULT => unreachable, |
| | 5497 | .INVAL => unreachable, // main purpose: debug InvalidValue error |
| | 5498 | else => unreachable, |
| | 5499 | } |
| | 5500 | } |
| | 5501 | |
| 5444 | pub const FutimensError = error{ | 5502 | pub const FutimensError = error{ |
| 5445 | /// times is NULL, or both tv_nsec values are UTIME_NOW, and either: | 5503 | /// 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 owner | 5504 | /// * the effective user ID of the caller does not match the owner |