From 888faa3c9f83c8205b3758203b6a1c44f3e7f53d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?kleines=20Filmr=C3=B6llchen?= Date: Fri, 21 Jan 2022 13:23:57 +0100 Subject: [PATCH] LibCore: Fix signal handling race condition in EventLoop The event loop is responsible for handling POSIX signals while it's running. The signal handler adds the signals to a wake pipe which is then read after the select'ing code in wait_for_event. Problems happen, however, when another signal comes in after the select wake: the signal will interrupt the next syscall, the `read` from the wake pipe, and the resulting EINTR in wait_for_event causes the program to crash. This is undesirable. Instead, we want to retry reading as long as we're interrupted. --- Userland/Libraries/LibCore/EventLoop.cpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/Userland/Libraries/LibCore/EventLoop.cpp b/Userland/Libraries/LibCore/EventLoop.cpp index 387ddd72dc..7fe465ceeb 100644 --- a/Userland/Libraries/LibCore/EventLoop.cpp +++ b/Userland/Libraries/LibCore/EventLoop.cpp @@ -5,6 +5,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -675,9 +676,17 @@ try_select_again: } if (FD_ISSET(s_wake_pipe_fds[0], &rfds)) { int wake_events[8]; - auto nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events)); + ssize_t nread; + // We might receive another signal while read()ing here. The signal will go to the handle_signal properly, + // but we get interrupted. Therefore, just retry while we were interrupted. + do { + errno = 0; + nread = read(s_wake_pipe_fds[0], wake_events, sizeof(wake_events)); + if (nread == 0) + break; + } while (nread < 0 && errno == EINTR); if (nread < 0) { - perror("read from wake pipe"); + perror("Core::EventLoop::wait_for_event: read from wake pipe"); VERIFY_NOT_REACHED(); } VERIFY(nread > 0);