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 ...@@ -67,6 +67,10 @@ typedef enum
static void static void
signal_handler (int sig) 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) switch (sig)
{ {
case SIGHUP: case SIGHUP:
...@@ -134,6 +138,8 @@ signal_handler (int sig) ...@@ -134,6 +138,8 @@ signal_handler (int sig)
* signal, but keep -Wswitch-default happy */ * signal, but keep -Wswitch-default happy */
break; break;
} }
errno = saved_errno;
} }
#endif /* DBUS_UNIX */ #endif /* DBUS_UNIX */
......
...@@ -1138,11 +1138,17 @@ static int babysit_sigchld_pipe = -1; ...@@ -1138,11 +1138,17 @@ static int babysit_sigchld_pipe = -1;
static void static void
babysit_signal_handler (int signo) 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'; char b = '\0';
again: again:
if (write (babysit_sigchld_pipe, &b, 1) <= 0) if (write (babysit_sigchld_pipe, &b, 1) <= 0)
if (errno == EINTR) if (errno == EINTR)
goto again; goto again;
errno = saved_errno;
} }
static void babysit (pid_t grandchild_pid, 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