Live data from Hacker News

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

boston.conman.org

21–30 of 98 posts

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

#21
Note that (a) the issue was with clearing the direction flag on signal handler entry, not saving it; and (b) it's since been fixed in the kernel to conform to the ABI (which GCC blindly trusted) [1].

And after reading that thread, I'm not as convinced as I was a few minutes ago that this was an obvious kernel issue. Yes, the kernel mismatched the published ABI, but callee-vs-caller save and setup is not always consistent, and for good reason.

E.g. registers are usually callee-save, since there are many registers and small functions use few of them. (This is what the kernel assumed.) But rarely-set/often-used flags (such as the flag in question) may make more sense as caller-save and even caller-setup, since this reduces save/setup overhead to only the cases where the flag is actually set. (This is what the ABI dictated and GCC assumed.)

[1] https://lkml.org/lkml/2008/3/5/306

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

#22

It isn't POSIX, but Linux does have the very useful signalfd, which creates a file descriptor that accepts signals. This is a good solution for some types of programs.

But as pointed in this old HN story it is useless in this case.

https://news.ycombinator.com/item?id=9564975

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

#23
post #18

Something that's always baffled me: why don't CPUs have a "save ALL state" and "restore ALL state" instructions? Why does every new set of CPU registers seem to require an OS update to save them on context switches?

The more state you save, the larger the latency in handling the interrupt. And the amount of state in modern CPUs can be quite large indeed.

Any idea how much it is? (just as a guess, I'd guess like maybe 8 KiB?)

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

#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.org/linux/man-pages/man2/sigreturn.2.html

Third, there was a similar discussion about restoring SS (segment stack) register in x86-64 signal code. First patch proposed by Bryan Ford: https://lkml.org/lkml/2005/10/5/176 . Then 10 years later by Andy Lutomirski: https://lkml.org/lkml/2014/7/11/564

Last one was merged into mainline. Then reversed. Sadly. Then applied again: https://github.com/torvalds/linux/commit/6c25da5ad55d48c41b8...

The gist: if you modify SS register in the signal handler you are screwed. The only way around it is to install a trampoline using "the famous dosemu iret hack" described here:

http://www.x86-64.org/pipermail/discuss/2007-May/009913.html

(the site is down, can anyone find a mirror?)

On Linux use signalfd(2) whenever you can http://man7.org/linux/man-pages/man2/signalfd.2.html (Ie: put signal handling back in event loop). That's the only sane way of dealing with signals.

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

#25
POSIX cares not one jot about Intel's CPU implementation, the assumption that memset is not async-signal safe because of something specific to x86 is ludicrous. As of IEEE Std 1003.1-2008, 2016 Edition memset() and lots of others beside are now Async-Signal safe, see http://pubs.opengroup.org/onlinepubs/9699919799/functions/V2.... That's in contrast to IEEE Std 1003.1, 2004 Edition which has a much shorter list which excludes memset(), see http://pubs.opengroup.org/onlinepubs/007904975/functions/xsh...

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

#26

Earlier quoted context omitted.

They do, now. On current Intel CPUs, you can use xsave and xrstor to save and load the complete state, including all new state information. Ring 0 code can ask the CPU for the size of that state (via CPUID leaf 0xd), and allocate the appropriate amount of space per task.

Oh wow. When did this change? I vaguely seem to remember that as recently as Windows 7 (or was it 8.0?) there was trouble with AVX2 or something, but I can't find the info anywhere at the moment.

Perhaps you're thinking of this debugger issue?

https://randomascii.wordpress.com/2013/03/11/should-this-win...

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

#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.

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

#30

Earlier quoted context omitted.

Oh wow. When did this change? I vaguely seem to remember that as recently as Windows 7 (or was it 8.0?) there was trouble with AVX2 or something, but I can't find the info anywhere at the moment.

Perhaps you're thinking of this debugger issue? https://randomascii.wordpress.com/2013/03/11/should-this-win...

Ah yes, good find, I believe this was one of them! I don't remember if there were more though, there might have been.
Post reply on HN