@@ -250,6 +250,15 @@ pub var argv: [][*:0]u8 = if (builtin.link_libc) undefined else switch (builtin.
250
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
262
/// To obtain errno, call this function with the return value of the
254
263
/// system function call. For some systems this will obtain the value directly
255
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
451
/// Causes abnormal process termination.
443
452
/// If linking against libc, this calls the abort() libc function. Otherwise
444
453
/// it raises SIGABRT followed by SIGKILL and finally lo
454
+ /// assume: Current signal handler for SIGABRT does **not call abort**.
445
455
pub fn abort () noreturn {
446
456
@setCold (true );
447
457
// MSVCRT abort() sometimes opens a popup window which is undesirable, so
@@ -454,11 +464,48 @@ pub fn abort() noreturn {
454
464
windows .kernel32 .ExitProcess (3 );
455
465
}
456
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
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
506
raise (SIG .KILL ) catch {};
507
+
508
+ // pid 1 might not be signalled in some containers
462
509
exit (127 );
463
510
}
464
511
if (builtin .os .tag == .uefi ) {
@@ -485,13 +532,13 @@ pub fn raise(sig: u8) RaiseError!void {
485
532
if (builtin .os .tag == .linux ) {
486
533
var set : sigset_t = undefined ;
487
534
// block application signals
488
- _ = linux . sigprocmask (SIG .BLOCK , & linux .app_mask , & set );
535
+ sigprocmask (SIG .BLOCK , & linux .app_mask , & set );
489
536
490
537
const tid = linux .gettid ();
491
538
const rc = linux .tkill (tid , sig );
492
539
493
540
// restore signal mask
494
- _ = linux . sigprocmask (SIG .SETMASK , & set , null );
541
+ sigprocmask (SIG .SETMASK , & set , null );
495
542
496
543
switch (errno (rc )) {
497
544
.SUCCESS = > return ,
@@ -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
5502
pub const FutimensError = error {
5445
5503
/// times is NULL, or both tv_nsec values are UTIME_NOW, and either:
5446
5504
/// * the effective user ID of the caller does not match the owner
0 commit comments