Post by Matthew DempskyI _think_ (although I don't have hard evidence) that the reason that
memcpy() is NOT async-signal-safe is to make it possible for x86
implementations that use the rep instruction prefix without having to
always use cld/std, and making it possible to save thread state with
fewer instructions per task swap.
This lkml thread has more details on gcc 4.3 vs. various kernels;
including some highlights I will quote here:
There is an industry-standard ABI document for x86-64 which proscribes
that DF will be clear on function entry (if memcpy() is always
forward-only, then DF is most likely to be set only during a memmove()
of overlapping memory where reverse directionality meets the contract of
memmove()). However, multiple OS's failed to follow the ABI (at least,
at the time this issue was raised; I'm not sure which, if any, of these
OS's have been patched in the meantime):
https://lkml.org/lkml/2008/3/5/343
"And for other kernels. I tested OpenBSD 4.1, FreeBSD 6.3, NetBSD 4.0,
they have the same behaviour as Linux, that is they don't clear DF
before calling the signal handler.
"I also tested Hurd, and it causes a kernel crash."
https://lkml.org/lkml/2008/3/5/518
"The issue is that the kernel is entered (due to a trap, interrupt or
whatever) and the state is saved. The kernel decides to revector
userspace to a signal handler. The kernel modifies the userspace state
to do so, but doesn't set DF=0.
"Upon return to userspace, the modified state kicks in. Thus the signal
handler is entered with DF from userspace at trap time, not DF=0.
"So it's an asynchronous state leak from one piece of userspace to another."
Therefore, it is still debatable whether this is a bug in the kernels
that must be fixed for leaking DF state into signal handlers, or a bug
in the compiler for making assumptions that DF=0 will be true on
function entry (even for signal handler functions), or a bug in the ABI
document for not matching existing practice, or merely the evidence that
simple string functions are not async-signal-safe and mandating them to
be safe would be too much of a burden on existing implementations, and
that signal handlers should use open-coded loops instead of any simple
libc string functions. But it is certainly food for thought.
Post by Matthew DempskyHm, that's an interesting point. Though on the other hand GCC and
Clang on x86 and x86-64 optimize large struct assignments by emitting
a call to memcpy(), and large struct assignments should be
async-signal-safe.
Compilers implementing a large struct copy in a signal handler via
memcpy() under the hood are presumably safe, even if the signal handler
is started with DF=1, because they presumably proved the two structs are
non-overlapping, at which point directionality no longer affects the
correctness of the copy. But there are probably other cases where
directionality matters, and where leaking the wrong directionality
either into or out of a signal handler could cause the copying of wrong
data or even reading beyond array bounds. Still, it seems like if the
kernels could be made to obey the ABI document and guarantee a known DF
state on signal handler entry, and restore prior DF state on signal
handler exit, then the simple string functions would behave as if they
are async-signal-safe even if they mess with DF.
--
Eric Blake eblake redhat com +1-919-301-3266
Libvirt virtualization library http://libvirt.org