Change:
// pipe I/O up to PIPE_BUF bytes should be atomic, and then // we want to be sure we *don't* run at_exit destructors as // we're being torn down regardless <del> assert!(output.write(&bytes).is_ok()); </del> <ins> rtassert!(output.write(&bytes).is_ok()); </ins> libc::_exit(1) } n => n,

Discussion:
On Unix-like OSes, uses an . If that fails, it will call , which is not signal-safe. It's better to use there. () shouldn't be used as a replacement, as, at least in glibc, it's not signal-safe<sup[1][2]</sup, although all of the C standard, the C++ standard, the POSIX standard, and Linux man-pages say it should be. [1] ;a=blob;f=stdlib/abort.c;h=;hb=refs/heads/master#l54 [2] <!-- TRIAGEBOTSTART --<!-- TRIAGEBOTASSIGNSTART --<!-- TRIAGEBOTASSIGNDATASTARTTRIAGEBOTASSIGNDATAEND --<!-- TRIAGEBOTASSIGNEND --<!-- TRIAGEBOT_END --
It seems that nobody is aware of this... I know many libraries (such as the glibc above) don't care about signal safety in such situation. If you're not aware of this, feel free to close this issue.
Closing as there is no response.
cc
This is a good catch. We certainly try to be signal-safe in such contexts, and failing to do so is a bug. Sorry to see that this didn't get a response. I'm reopening this, as it remains a bug.
I discovered that if is not signal-safe (in glibc), then is not signal-safe, so the signal handlers in the standard library that call is actually not signal-safe: Maybe I should open a new issue or report the bug to glibc...
lists as async-signal-safe. If it isn't in practice async-signal-safe in glibc, that's a bug and you should report it.
On Mon, Jul 20, 2020 at 01:32:22AM -0700, hyd-dev wrote: I just realized if is not signal-safe (in glibc), then is not signal-safe, so the signal handlers in the standard library that call is actually not signal-safe: Maybe I should open a new issue or report the bug to glibc. Reported as
So I think can be used, and is suitable as a replacement. WDYT?
Should this be fixed like that?
Given the above research, I don't think is safe to use either.
Using seems like a potentially reasonable approach here. ( just calls .)

I would prefer just using since that is precisely what it was designed for.
That call chain is --, which on unix calls .
The note about flushing files isn't something we can rely on: Up until glibc 2.26, if the abort() function caused process termination, all open streams were closed and flushed (as with fclose(3)). However, in some cases this could result in deadlocks and data corruption. Therefore, starting with glibc 2.27, abort() terminates the process without flushing streams. POSIX.1 permits either possible behavior, saying that abort() "may include an attempt to effect fclose() on all open streams".
In upstream glibc the goal is for abort() to be AS-safe as required by the standard and it should be today (after glibc 2.27). In fact doing anything superfluous during the abort() generally constitutes a security hazard because the process can be in an unknown state when corruption is detected and the abort() called. For the sake of reducing restart latency and avoiding executing any compromised parts of the process we shut down as quickly as possible. We strongly recommend out-of-process backtracing to avoid needing to run any of that code in the process with bad or unknown state.
It's not. It tries to .
Example demonstrating a deadlock. After a dozen of so runs leaves deadlocked children behind: At least the conditions for deadlock are quite unlikely, since both a child process and a thread in the parent process must abort. The musl implementation looks correct (it also uses a lock, which by itself is only a weak indicator of a potential issue).
You may want to post that on the glibc bug report here:
I have a fix for glibc. Locks are basically required to avoid seeing the unmasked signal state in the child. However, you have to take that lock during fork to ensure that you own and can unlock the lock in the child (avoids the deadlock). The regression test was not straight forward to write and on average it only reproduces once every 100-600 seconds on an x86_64 VM with 4vCPU. That's good enough though and I run the test for 20s to probabilistically try to catch if the defect comes back.

On average if I ran the regression test just once per dev-test cycle it might take something like 32 years to show the defect :-( Thankfully more people than just the dev-test cycle will be using the API.
Unfortunately, avoiding may still be required after the patch lands, to wait for it to be released and included in GNU/Linux distributions.
I think we can make call when using glibc and then use in .
Please don't use . If you really want then raise instead.
It is: Although you should probably use , and to properly implement an replacement (all of which are also signal-safe).
Sorry. I confused. You're correct.
says is equivalent to . I think , and just can be used to implement the replacement. I can submit a PR to do that. claim
IMO we should just leave it as glibc's acknowledged bug, unless folks are actively hitting this problem. While we do hope to be technically "pure", the actual abort race seems like a very artificial situation that I doubt is a problem in practice.
I've found that if I have to avoid and use , I almost need to reimplement and port its tests to . Maybe it's really better to keep using and just replace the with . Fair. Also, thanks for fixing the race in glibc. I can still submit a PR to just change the to . That unsafety shouldn't be ignored.