Live data from Hacker News

Why isn't memset() async-signal-safe?

boston.conman.org

41–50 of 98 posts

Re: Why isn't memset() async-signal-safe?

#41
post #38

I was under impression that signals are delivered to a process only when process is executing a syscall. Given the fact that memset or memmove are note executing any syscalls they will not be interrupted by a signal handler. Am i wrong?

Async signal safety refers to the functions being called in the handler, not the interrupted code. Also signals can interrupt the code just as normal thread preemption would, not only while the thread is inside a system call.

Re: Why isn't memset() async-signal-safe?

#42
post #27
post #24

Couple of things. First, I don't think that's true nowadays. The discussion points that this (not restoring DF on signal return) is a kernel bug and should be fixed: https://lkml.org/lkml/2008/3/5/531 Second, the kernel tries to avoid doing too much work in the signal return code. It tries hard do _avoid_ heavy XSAVE and just preserve only the needed registers. This is the job of sigreturn(2) syscall btw. http://man7…

I mean, kernel bug or no, if that's how it actually works, then it isn't actually safe to be handle signals while executing these functions. If people are still working to change the code and standards we hold the code to, then you can't push changes that rely on the new behavior without introducing some truly bizarre race conditions.

The bug is 8 years old. At some point you can assume it's been fixed.

Re: Why isn't memset() async-signal-safe?

#43
post #32
post #10

The post makes it a bit unclear, so for the record: there's no theoretical reason the direction flag should be a problem. Just like any other callee-saved register, the kernel needs to save it to the stack and restore it when returning from the signal handler; there's nothing about the direction flag that makes it harder to do so, even if a signal handler is interrupting another signal handler or whatnot. And before…

I'm confused too. On x86, EFLAGS (of which the direction flag is bit 10) is absolutely preserved across signal delivery. It's the spot where the comparison result bits go, so if the issue in the linked blog post was real, it would be impossible to deliver a signal across a test/jump pair, making basically all compiled code signal-unsafe. I don't know what historical architectures may have had a bug with this, but it'…

It's about whether it's cleared entering a signal handler or not

https://lkml.org/lkml/2008/3/5/207

is the first message.

Basically: ABI implementation bug in kernel. https://lkml.org/lkml/2008/3/5/231

GCC started actually relying on the ABI being correct in version 4.3, folks noticed bug.

Re: Why isn't memset() async-signal-safe?

#45
This article seems flat out wrong. Since the direction flag is correctly saved and restored, everything is cool.

When some code is interrupted and the signal or interrupt handler calls memmove, that memmove will set up the direction flag for itself correctly. Its entire execution is nested within the handler. If it is interrupted by a nested interrupt, that nested one will restore the flag.

Now if an implementation of the memset function happens not to care about that flag, so that it changes direction from call to call, that's not a signal or interrupt problem! The flag can have arbitrary value in on entry to memcpy in an ordinary situation not involving threads or signals.

The moral is: never use the looping primitives on Intel without setting up the direction flag, if you care about reproducibility.

It goes without saying that the flag is part of the machine state; any machine context saving mechanism (for async situations) is broken if it neglects that flag.

Re: Why isn't memset() async-signal-safe?

#46
post #35

Any time anybody tells you that POSIX isn't terrible, the subject of this article is the sort of thing you need to bear in mind. (For a long time, I thought that literally the only thing that POSIX didn't fuck up is the way they don't have any analogue to MAXIMUM_WAIT_OBJECTS. But then, after I gained more experience with POSIX, I realised that even if I don't understand how, this too was probably also something they…

Posix is terrible. But I'm not sure we have anything better.

MAXIMUM_WAIT_OBJECTS is also terrible of course, but even apart from that Win32 is not bright, at all. The doc contains so little details (or worse is sometime even false) that the real doc when you start to ask serious questions is ReactOS, Wine, or even the NT/2000 source leaks, and then IDA. Compared to that, Posix is actually documented and implemented mostly correctly by tons of OSes. Its easy to ship an API with basically no spec (so nobody can tell you that there is a bug when they find one - actually even if there were some real specs about Win32 I think there is public no way to report bugs in there to MS!), and that does not have to be compatible with any other implementation...

Re: Why isn't memset() async-signal-safe?

#47
post #34

Slightly terrifying is the optimizer may very well replace the following while(n--) *m++ = c; With a call to the built in memset()

It does a lot more replacements, depending on the architecture. Even a simple a/b or a%b will get replaced with function call on many archs.

Re: Why isn't memset() async-signal-safe?

#48
post #44
post #34

Slightly terrifying is the optimizer may very well replace the following while(n--) *m++ = c; With a call to the built in memset()

I'm fairly inexperienced on this matter. Can you give a real life example where this would be a bad thing?

If memset is actually not async signal safe on some target, and a compiler targetting the same does that transformation, the end results are very unsound...

Re: Why isn't memset() async-signal-safe?

#49
post #24

Couple of things. First, I don't think that's true nowadays. The discussion points that this (not restoring DF on signal return) is a kernel bug and should be fixed: https://lkml.org/lkml/2008/3/5/531 Second, the kernel tries to avoid doing too much work in the signal return code. It tries hard do _avoid_ heavy XSAVE and just preserve only the needed registers. This is the job of sigreturn(2) syscall btw. http://man7…

The bug wasn't "not restoring DF on signal return" - it was always saved and restored correctly. The bug was not clearing DF on signal entry.

Re: Why isn't memset() async-signal-safe?

#50
post #39

Seems like a good argument against an architecture having stateful flags that affect the execution of other instructions. Or, at least, against having such flags and not including them in the state saved and restored when switching contexts (including to signals).

Processors are inherently extremely stateful; this is an argument against having unix-style signals.

No disagreement there. In a new OS that doesn't need 100% POSIX compatibility, I'd eliminate the standard signal model, and only have signalfd (plus a SIGKILL equivalent and a separate stop/continue mechanism similar to SIGSTOP/SIGCONT).
Post reply on HN