From 57ab8acc0e942e14a48d497af60396baf304d183 Mon Sep 17 00:00:00 2001 From: illustris Date: Tue, 4 Jan 2022 08:10:05 +0530 Subject: [PATCH] X11: Fix segfault when _glfw.x11.display is higher than 1024 FD_SETSIZE is hardcoded to 1024 in glibc. See the bugs section of the select call for more info. In some cases, it is possible for _glfw.x11.display to be larger than FD_SETSIZE, causing a segfault or buffer overflow. Replacing select() with poll() seems to be the recommended solution: - https://www.man7.org/linux/man-pages/man2/select.2.html#BUGS - https://access.redhat.com/solutions/488623 - https://stackoverflow.com/questions/7976388/increasing-limit-of-fd-setsize-and-select/7977082#7977082 --- src/x11_window.c | 40 ++++++++++++++++++++++++++++++++-------- 1 file changed, 32 insertions(+), 8 deletions(-) diff --git a/src/x11_window.c b/src/x11_window.c index 61e4fd6d..2d4b2692 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -41,6 +41,10 @@ #include #include +#if defined(__linux__) +#include +#endif + // Action for EWMH client messages #define _NET_WM_STATE_REMOVE 0 #define _NET_WM_STATE_ADD 1 @@ -63,31 +67,47 @@ // static GLFWbool waitForEvent(double* timeout) { - fd_set fds; const int fd = ConnectionNumber(_glfw.x11.display); - int count = fd + 1; + int count; #if defined(__linux__) - if (_glfw.linjs.inotify > fd) - count = _glfw.linjs.inotify + 1; + struct pollfd pfd[2]; +#else + fd_set fds; + count = fd + 1; #endif + for (;;) { +#if defined(__linux__) + pfd[0].fd = fd; + pfd[0].events = POLLIN; + if (_glfw.linjs.inotify > 0) + { + count = 2; + pfd[1].fd = _glfw.linjs.inotify; + pfd[1].events = POLLIN; + } + else + count = 1; +#else FD_ZERO(&fds); FD_SET(fd, &fds); -#if defined(__linux__) - if (_glfw.linjs.inotify > 0) - FD_SET(_glfw.linjs.inotify, &fds); #endif if (timeout) { const long seconds = (long) *timeout; const long microseconds = (long) ((*timeout - seconds) * 1e6); - struct timeval tv = { seconds, microseconds }; const uint64_t base = _glfwPlatformGetTimerValue(); +#if defined(__linux__) + int timeout_ms = (seconds * 1000) + (microseconds / 1000); + const int result = poll(pfd, count, timeout_ms); +#else + struct timeval tv = { seconds, microseconds }; const int result = select(count, &fds, NULL, NULL, &tv); +#endif const int error = errno; *timeout -= (_glfwPlatformGetTimerValue() - base) / @@ -98,7 +118,11 @@ static GLFWbool waitForEvent(double* timeout) if ((result == -1 && error == EINTR) || *timeout <= 0.0) return GLFW_FALSE; } +#if defined(__linux__) + else if (poll(pfd, count, 0) != -1 || errno != EINTR) +#else else if (select(count, &fds, NULL, NULL, NULL) != -1 || errno != EINTR) +#endif return GLFW_TRUE; } }