Live data from Hacker News

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

boston.conman.org

71–80 of 98 posts

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

#71
post #58
post #53

Earlier quoted context omitted.

> 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: I'm not sure what you mean. This issue is fixed, so SS works exactly the way you would expec…

Strange or not, linux did not restore SS on sigreturn in 64 bit mode. The point of explaining that is to emphasize that the issue described in the blog post is not the only one in this code (the code doing entering / exiting signal handlers). The issue is fixed indeed, as for Feb 17, 2016.

Okay, I read your post as meaning that it was still broken.

FWIW, I don't consider it sad that my first attempt was reverted. I inadvertently broke some assumptions that a real program (DOSEMU) was making, and Linux takes backwards compatibility quite seriously. The second version was better.

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

#72
post #55

There are a whole bunch of almost-correct comments here along with a surprising number of "it's been so long it must be fixed". The alleged bug is that Linux didn't clear DF on signal entry. (This has nothing to do with what is saved or restored. Flags have to be saved and restored and, AFAIK, always were.) The x86 ABI is crystal clear: C functions are called with DF clear. Neither glibc nor Linux cleared it before c…

That doesn't mean anything when talking about POSIX.

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

#73

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 o…

> The flag can have arbitrary value in on entry to memcpy in an ordinary situation not involving threads or signals.

It can not have arbitrary value on entry. x86-64 ABI mandates that the flag is cleared before any function is called (3.2.1 Registers and the Stack Frame: "The direction flag in the %eflags register must be clear on function entry, and on function return.")

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

#74
post #52

Earlier quoted context omitted.

How would you handle being able to trap and fix bad memory access (i.e. hooking SIGSEGV/SIGBUS) with this scheme? Lots of programs use this for various reasons; off the top of my head at least a few generational GCs implement their write barrier by setting pages read-only and noticing the trap and resetting RW on SEGV... (Yes, I believe something like card marking is more performant than this in several ways on moder…

For trapping memory accesses, either something like userfaultfd, or otherwise handling segfaults via a signalfd from another thread with its own independent stack. (I'd also eliminate limitations about using a signalfd only within the same process that would have received the signals.) Or, if you just need a "dirty page" bit, add a dedicated mechanism for that, which can use hardware features to run much faster witho…

>signalfd from another thread with its own independent stack.

This has similar reentrancy issues to signals.

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

#75
post #33

Earlier quoted context omitted.

The CPU designers could have protected against this by randomly fluctuating the size of the xsave'd data.

At the cost of extra bandwidth and interrupt latency.

Yes, but only marginally if they changed the size only 1 out of 1000 times.

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

#76
post #68

Earlier quoted context omitted.

I'm also not an expert, but I think the bigger cost here is memory latency. Size correlates to, but scales differently than the switching cost of registers because it's zero sum. A register saved is a register waited on, twice. There's also the cost of decoding and executing the instructions to store / restore the register values on both ends.

I don't get it, you have to save and restore all the state on context switches either way. The only question is whether you're doing it with a generic instruction or through some other more specialized instructions. It's not a question of whether they should be saved and restored at all. That said, I'm confused why you replied to my comment above, since it's totally off-topic. This thread chain was asking how much st…

> I don't get it, you have to save and restore all the state on context switches either way.

Actually, you don't. I'm not up to date as to what's done in this direction by current kernels, but a while back, a patch was merged that disabled floating point and MMX operations by default for a process, and enabled it for a while only when some FP or MMX instruction lead to an exception, which then allowed the kernel to avoid saving and restoring FP state on processes that weren't actually doing any FP/MMX operations.

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

#77
post #72
post #55

There are a whole bunch of almost-correct comments here along with a surprising number of "it's been so long it must be fixed". The alleged bug is that Linux didn't clear DF on signal entry. (This has nothing to do with what is saved or restored. Flags have to be saved and restored and, AFAIK, always were.) The x86 ABI is crystal clear: C functions are called with DF clear. Neither glibc nor Linux cleared it before c…

That doesn't mean anything when talking about POSIX.

POSIX doesn't guarantee that memset is async-signal-safe, that is clear enough, and flags like this are even a reasonable rationale. But it sounds like post-2008 memset is and should be async-signal-safe on Linux. Are there relevant systems on which it isn't? IME it's impractical to write code that will work on all POSIX-compliant systems as the standard leaves too much undefined and there is no testsuite that will let you determine when your code is depending on something beyond the minimum requirements of POSIX.

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

#79
post #78

What I've never seen discussions on signal safety address is: why must an OS have signals to begin with?

This (signal) is the de-facto communication mechanism to notify a program that an unexpected event just occurred (typically, a SEGV). This mechanism needs to interrupt the normal program flow (because you can not restart an invalid access most of the time), possibly interrupting a C-library call (such as malloc, reason why malloc is not async-signal-safe generally). What would you do instead ? On Windows systems, there is a built-in "__try / __except" mechanism ("structured exception handling", SEH), which provides exception-like catch in plain C with proprietary extension to C. This is probably not such a better method.

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

#80
post #77
post #72

Earlier quoted context omitted.

That doesn't mean anything when talking about POSIX.

POSIX doesn't guarantee that memset is async-signal-safe, that is clear enough, and flags like this are even a reasonable rationale. But it sounds like post-2008 memset is and should be async-signal-safe on Linux. Are there relevant systems on which it isn't? IME it's impractical to write code that will work on all POSIX-compliant systems as the standard leaves too much undefined and there is no testsuite that will l…

Welcome to POSIX.

As for GNU/Linux, can you assure memset works that way in all hardware platforms supported by Linux?

Even it does, no one intending to write portable UNIX code can rely on it anyway.

Post reply on HN