Commit 3d538ced authored by Simon McVittie's avatar Simon McVittie

Make sure non-aborting signal handlers save and restore errno

If an async signal interrupts some function, we can have this
anti-pattern:

    /* in normal code */
    result = some_syscall (); /* fails, e.g. errno = EINVAL */

        /* interrupted by async signal handler */
        write (...); /* fails, e.g. errno = ENOBUFS */

    /* back to normal code */
    if (errno == EINVAL) /* problem! it should be but it isn't */

The solution is for signal handlers to save and restore errno.

This is unnecessary for signal handlers that can't touch errno (like
the one in dbus-launch that just sets a flag), and for signal handlers
that never return (like the one in test-utils-glib for timeouts).

Bug: https://bugs.freedesktop.org/show_bug.cgi?id=103010Signed-off-by: Simon McVittie's avatarSimon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall's avatarPhilip Withnall <withnall@endlessm.com>
parent 3d557ff7
......@@ -67,6 +67,10 @@ typedef enum
static void
signal_handler (int sig)
{
/* Signal handlers that might set errno must save and restore the errno
* that the interrupted function might have been relying on. */
int saved_errno = errno;
switch (sig)
{
case SIGHUP:
......@@ -134,6 +138,8 @@ signal_handler (int sig)
* signal, but keep -Wswitch-default happy */
break;
}
errno = saved_errno;
}
#endif /* DBUS_UNIX */
......
......@@ -1138,11 +1138,17 @@ static int babysit_sigchld_pipe = -1;
static void
babysit_signal_handler (int signo)
{
/* Signal handlers that might set errno must save and restore the errno
* that the interrupted function might have been relying on. */
int saved_errno = errno;
char b = '\0';
again:
if (write (babysit_sigchld_pipe, &b, 1) <= 0)
if (errno == EINTR)
goto again;
errno = saved_errno;
}
static void babysit (pid_t grandchild_pid,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment