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=103010
Signed-off-by: Simon McVittie <smcv@collabora.com>
Reviewed-by: Philip Withnall <withnall@endlessm.com>
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:
* signal, but keep -Wswitch-default happy */
break;
}
+
+ errno = saved_errno;
}
#endif /* DBUS_UNIX */
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,