Browse Source

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.
kleines Filmröllchen 3 years ago
parent
commit
888faa3c9f
1 changed files with 11 additions and 2 deletions
  1. 11 2
      Userland/Libraries/LibCore/EventLoop.cpp

+ 11 - 2
Userland/Libraries/LibCore/EventLoop.cpp

@@ -5,6 +5,7 @@
  * SPDX-License-Identifier: BSD-2-Clause
  */
 
+#include <AK/Assertions.h>
 #include <AK/Badge.h>
 #include <AK/Debug.h>
 #include <AK/Format.h>
@@ -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);