From 6de70d82522a8b884b1b271686707697ce193238 Mon Sep 17 00:00:00 2001 From: Ivor Wanders Date: Sat, 9 Aug 2025 11:13:20 -0400 Subject: [PATCH 1/8] X11: Prevent BadWindow when creating small windows The glfwCreateWindow function ensures that the width and height are at least greater or equal than zero, but on X11 it is invalid to create a window with dimensions that equal zero, see [1]. This change ensures that the dimensions passed to XCreateWindow are at least 1 by 1. This issue was detected in [2], where a call to glfwCreateWindow was done to request a 1x1 window, with a _glfw.x11.contentScaleX of less than 1.0 (0.958333) this results in a request for a 0x0 window which then causes an BadWindow error from X11. [1]: https://gitlab.freedesktop.org/xorg/lib/libx11/-/blob/e003f52661679e95b51ff24e317af6178fe2a73c/specs/libX11/CH03.xml#L1333-1337 [2]: https://github.com/WerWolv/ImHex/pull/2390 --- CONTRIBUTORS.md | 1 + README.md | 2 ++ src/x11_window.c | 4 ++++ 3 files changed, 7 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index cfb4f42ca..e3956e61d 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -282,6 +282,7 @@ video tutorials. - Corentin Wallez - Torsten Walluhn - Patrick Walton + - Ivor Wanders - Jim Wang - Xo Wang - Andre Weissflog diff --git a/README.md b/README.md index 1c7ced36e..5e882e277 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ information on what to include when reporting a bug. - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to `GLFW_NATIVE_CONTEXT_API` (#2518) + - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale + less than 1 (#2754) ## Contact diff --git a/src/x11_window.c b/src/x11_window.c index 986bfb93b..65d7eb2cb 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -576,6 +576,10 @@ static GLFWbool createNativeWindow(_GLFWwindow* window, height *= _glfw.x11.contentScaleY; } + // The dimensions must be nonzero, or a BadValue error results. + width = _glfw_max(1, width); + height = _glfw_max(1, height); + int xpos = 0, ypos = 0; if (wndconfig->xpos != GLFW_ANY_POSITION && wndconfig->ypos != GLFW_ANY_POSITION) From 4df5129529b1af57d04a51f09145da5079822c3e Mon Sep 17 00:00:00 2001 From: Drew Weymouth Date: Sat, 6 Sep 2025 07:33:27 -0700 Subject: [PATCH 2/8] X11: check crtcInfo for NULL when polling monitors --- CONTRIBUTORS.md | 1 + README.md | 1 + src/x11_monitor.c | 5 +++++ 3 files changed, 7 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index e3956e61d..0e1d88342 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -287,6 +287,7 @@ video tutorials. - Xo Wang - Andre Weissflog - Jay Weisskopf + - Drew Weymouth - Frank Wille - Andy Williams - Joel Winarske diff --git a/README.md b/README.md index 5e882e277..586d6be25 100644 --- a/README.md +++ b/README.md @@ -145,6 +145,7 @@ information on what to include when reporting a bug. - [Wayland] Bugfix: The cursor position was not updated when clicking through from a modal to the content area - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) + - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface` - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 3af827520..74c57ed01 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -151,6 +151,11 @@ void _glfwPollMonitorsX11(void) } XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); + if (!ci) { + XRRFreeOutputInfo(oi); + continue; + } + if (ci->rotation == RR_Rotate_90 || ci->rotation == RR_Rotate_270) { widthMM = oi->mm_height; From 936307558ee25bf5d50d7ecf22972efd4c3abd4f Mon Sep 17 00:00:00 2001 From: Doug Binks Date: Sat, 8 Nov 2025 10:37:52 +0000 Subject: [PATCH 3/8] X11: Clamp w,h in glfwSetWindowSize to >= 1 - prevents BadValue error and program exit --- README.md | 5 +++-- src/x11_window.c | 4 ++++ 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 586d6be25..528054e2c 100644 --- a/README.md +++ b/README.md @@ -146,12 +146,13 @@ information on what to include when reporting a bug. from a modal to the content area - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) + - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale + less than 1 (#2754) + - [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface` - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to `GLFW_NATIVE_CONTEXT_API` (#2518) - - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale - less than 1 (#2754) ## Contact diff --git a/src/x11_window.c b/src/x11_window.c index 65d7eb2cb..02c4ab58d 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2207,6 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) { + // The dimensions must be nonzero, or a BadValue error results. + width = _glfw_max(1, width); + height = _glfw_max(1, height); + if (window->monitor) { if (window->monitor->window == window) From 162896e5b9a40dc382c5c438cd12c90a5ff86ddd Mon Sep 17 00:00:00 2001 From: Doug Binks Date: Fri, 14 Nov 2025 16:35:47 +0000 Subject: [PATCH 4/8] Wayland: free modules at end of terminate function - Fixes #2744 --- README.md | 2 ++ src/egl_context.c | 3 ++- src/wl_init.c | 52 +++++++++++++++++++++++++++-------------------- 3 files changed, 34 insertions(+), 23 deletions(-) diff --git a/README.md b/README.md index 528054e2c..9bad25a0f 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,8 @@ information on what to include when reporting a bug. a modal to a fallback decoration - [Wayland] Bugfix: The cursor position was not updated when clicking through from a modal to the content area + - [Wayland] Bugfix: free modules at end of terminate function to resolve + potential segmentation fault (#2744) - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale diff --git a/src/egl_context.c b/src/egl_context.c index 0ef7f7295..921d5c6eb 100644 --- a/src/egl_context.c +++ b/src/egl_context.c @@ -555,7 +555,8 @@ void _glfwTerminateEGL(void) _glfw.egl.display = EGL_NO_DISPLAY; } - if (_glfw.egl.handle) + // Free modules only after all wayland termination functions are called + if (_glfw.egl.handle && _glfw.platform.platformID != GLFW_PLATFORM_WAYLAND) { _glfwPlatformFreeModule(_glfw.egl.handle); _glfw.egl.handle = NULL; diff --git a/src/wl_init.c b/src/wl_init.c index ef9e45036..704906381 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -907,18 +907,6 @@ void _glfwTerminateWayland(void) libdecor_unref(_glfw.wl.libdecor.context); } - if (_glfw.wl.libdecor.handle) - { - _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); - _glfw.wl.libdecor.handle = NULL; - } - - if (_glfw.wl.egl.handle) - { - _glfwPlatformFreeModule(_glfw.wl.egl.handle); - _glfw.wl.egl.handle = NULL; - } - if (_glfw.wl.xkb.composeState) xkb_compose_state_unref(_glfw.wl.xkb.composeState); if (_glfw.wl.xkb.keymap) @@ -927,21 +915,11 @@ void _glfwTerminateWayland(void) xkb_state_unref(_glfw.wl.xkb.state); if (_glfw.wl.xkb.context) xkb_context_unref(_glfw.wl.xkb.context); - if (_glfw.wl.xkb.handle) - { - _glfwPlatformFreeModule(_glfw.wl.xkb.handle); - _glfw.wl.xkb.handle = NULL; - } if (_glfw.wl.cursorTheme) wl_cursor_theme_destroy(_glfw.wl.cursorTheme); if (_glfw.wl.cursorThemeHiDPI) wl_cursor_theme_destroy(_glfw.wl.cursorThemeHiDPI); - if (_glfw.wl.cursor.handle) - { - _glfwPlatformFreeModule(_glfw.wl.cursor.handle); - _glfw.wl.cursor.handle = NULL; - } for (unsigned int i = 0; i < _glfw.wl.offerCount; i++) wl_data_offer_destroy(_glfw.wl.offers[i].offer); @@ -1001,6 +979,36 @@ void _glfwTerminateWayland(void) if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); + // Free modules only after all wayland termination functions are called + if (_glfw.egl.handle) + { + _glfwPlatformFreeModule(_glfw.egl.handle); + _glfw.egl.handle = NULL; + } + + if (_glfw.wl.libdecor.handle) + { + _glfwPlatformFreeModule(_glfw.wl.libdecor.handle); + _glfw.wl.libdecor.handle = NULL; + } + + if (_glfw.wl.egl.handle) + { + _glfwPlatformFreeModule(_glfw.wl.egl.handle); + _glfw.wl.egl.handle = NULL; + } + + if (_glfw.wl.xkb.handle) + { + _glfwPlatformFreeModule(_glfw.wl.xkb.handle); + _glfw.wl.xkb.handle = NULL; + } + if (_glfw.wl.cursor.handle) + { + _glfwPlatformFreeModule(_glfw.wl.cursor.handle); + _glfw.wl.cursor.handle = NULL; + } + _glfw_free(_glfw.wl.clipboardString); } From ebff6606ee1e30f12859c6c308452110022a4aa8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 1 Sep 2025 17:27:07 +0200 Subject: [PATCH 5/8] Simplify test for shared library build --- CMakeLists.txt | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 398b36eb1..063533c4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -38,11 +38,7 @@ set(GLFW_LIBRARY_TYPE "${GLFW_LIBRARY_TYPE}" CACHE STRING "Library type override for GLFW (SHARED, STATIC, OBJECT, or empty to follow BUILD_SHARED_LIBS)") if (GLFW_LIBRARY_TYPE) - if (GLFW_LIBRARY_TYPE STREQUAL "SHARED") - set(GLFW_BUILD_SHARED_LIBRARY TRUE) - else() - set(GLFW_BUILD_SHARED_LIBRARY FALSE) - endif() + string(COMPARE EQUAL "${GLFW_LIBRARY_TYPE}" "SHARED" GLFW_BUILD_SHARED_LIBRARY) else() set(GLFW_BUILD_SHARED_LIBRARY ${BUILD_SHARED_LIBS}) endif() From 1ce855b0b1c8c7418ef2925d75f3b7f366ff5cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Mon, 1 Sep 2025 18:43:26 +0200 Subject: [PATCH 6/8] Wayland: Fix missing checks for optional protocol --- README.md | 2 ++ src/wl_window.c | 14 +++++++++++++- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 9bad25a0f..89aaaac95 100644 --- a/README.md +++ b/README.md @@ -146,6 +146,8 @@ information on what to include when reporting a bug. from a modal to the content area - [Wayland] Bugfix: free modules at end of terminate function to resolve potential segmentation fault (#2744) + - [Wayland] Bugfix: Confining or disabling the cursor could segfault on + compositors without `pointer-constraints-unstable-v1` - [X11] Bugfix: Running without a WM could trigger an assert (#2593,#2601,#2631) - [X11] Bugfix: Occasional crash when an idle display awakes (#2766) - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale diff --git a/src/wl_window.c b/src/wl_window.c index 4220d17e0..1bb32f5f0 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -2974,10 +2974,16 @@ static void lockPointer(_GLFWwindow* window) if (!_glfw.wl.relativePointerManager) { _glfwInputError(GLFW_FEATURE_UNAVAILABLE, - "Wayland: The compositor does not support pointer locking"); + "Wayland: The compositor does not support relative pointer motion"); return; } + if (!_glfw.wl.pointerConstraints) + { + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The compositor does not support locking the pointer"); + } + window->wl.relativePointer = zwp_relative_pointer_manager_v1_get_relative_pointer( _glfw.wl.relativePointerManager, @@ -3025,6 +3031,12 @@ static const struct zwp_confined_pointer_v1_listener confinedPointerListener = static void confinePointer(_GLFWwindow* window) { + if (!_glfw.wl.pointerConstraints) + { + _glfwInputError(GLFW_FEATURE_UNAVAILABLE, + "Wayland: The compositor does not support confining the pointer"); + } + window->wl.confinedPointer = zwp_pointer_constraints_v1_confine_pointer( _glfw.wl.pointerConstraints, From 08449b71830c82d5341b97d3eb84261106552ace Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Tue, 25 Nov 2025 19:46:34 +0100 Subject: [PATCH 7/8] Linux: Add missing header for ioctl Fixes #2778 --- CONTRIBUTORS.md | 1 + README.md | 1 + src/linux_joystick.c | 1 + 3 files changed, 3 insertions(+) diff --git a/CONTRIBUTORS.md b/CONTRIBUTORS.md index 0e1d88342..031962ecd 100644 --- a/CONTRIBUTORS.md +++ b/CONTRIBUTORS.md @@ -162,6 +162,7 @@ video tutorials. - Marcel Metz - Liam Middlebrook - mightgoyardstill + - Mihail - Ave Milia - Icyllis Milica - Jonathan Miller diff --git a/README.md b/README.md index 89aaaac95..b27ea51dd 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ information on what to include when reporting a bug. - [X11] Bugfix: Prevent BadWindow when creating small windows with a content scale less than 1 (#2754) - [X11] Bugfix: Clamp width and height to >= 1 to prevent BadValue error and app exit + - [Linux] Bugfix: The header for `ioctl` was only implicitly included (#2778) - [Null] Added Vulkan 'window' surface creation via `VK_EXT_headless_surface` - [Null] Added EGL context creation on Mesa via `EGL_MESA_platform_surfaceless` - [EGL] Allowed native access on Wayland with `GLFW_CONTEXT_CREATION_API` set to diff --git a/src/linux_joystick.c b/src/linux_joystick.c index d8a916b08..e4d2852b3 100644 --- a/src/linux_joystick.c +++ b/src/linux_joystick.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include From dbadda26835ec5089ef922e6c290bcf58cf12056 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Camilla=20L=C3=B6wy?= Date: Thu, 14 Aug 2025 18:03:35 +0200 Subject: [PATCH 8/8] Formatting --- src/win32_init.c | 3 ++- src/wl_init.c | 4 +++- src/wl_platform.h | 8 ++++++-- src/wl_window.c | 9 ++++++--- src/x11_monitor.c | 3 ++- src/x11_window.c | 4 ++-- 6 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/win32_init.c b/src/win32_init.c index 6b6e9d08e..90e47670e 100644 --- a/src/win32_init.c +++ b/src/win32_init.c @@ -528,7 +528,8 @@ void _glfwUpdateKeyNamesWin32(void) if (key >= GLFW_KEY_KP_0 && key <= GLFW_KEY_KP_ADD) { - const UINT vks[] = { + const UINT vks[] = + { VK_NUMPAD0, VK_NUMPAD1, VK_NUMPAD2, VK_NUMPAD3, VK_NUMPAD4, VK_NUMPAD5, VK_NUMPAD6, VK_NUMPAD7, VK_NUMPAD8, VK_NUMPAD9, VK_DECIMAL, VK_DIVIDE, diff --git a/src/wl_init.c b/src/wl_init.c index 704906381..d32c4adf4 100644 --- a/src/wl_init.c +++ b/src/wl_init.c @@ -979,7 +979,8 @@ void _glfwTerminateWayland(void) if (_glfw.wl.cursorTimerfd >= 0) close(_glfw.wl.cursorTimerfd); - // Free modules only after all wayland termination functions are called + // Free modules only after all Wayland termination functions are called + if (_glfw.egl.handle) { _glfwPlatformFreeModule(_glfw.egl.handle); @@ -1003,6 +1004,7 @@ void _glfwTerminateWayland(void) _glfwPlatformFreeModule(_glfw.wl.xkb.handle); _glfw.wl.xkb.handle = NULL; } + if (_glfw.wl.cursor.handle) { _glfwPlatformFreeModule(_glfw.wl.cursor.handle); diff --git a/src/wl_platform.h b/src/wl_platform.h index c3e456931..bdadb657e 100644 --- a/src/wl_platform.h +++ b/src/wl_platform.h @@ -136,18 +136,22 @@ struct wl_output; #define GLFW_WAYLAND_MONITOR_STATE _GLFWmonitorWayland wl; #define GLFW_WAYLAND_CURSOR_STATE _GLFWcursorWayland wl; -struct wl_cursor_image { +struct wl_cursor_image +{ uint32_t width; uint32_t height; uint32_t hotspot_x; uint32_t hotspot_y; uint32_t delay; }; -struct wl_cursor { + +struct wl_cursor +{ unsigned int image_count; struct wl_cursor_image** images; char* name; }; + typedef struct wl_cursor_theme* (* PFN_wl_cursor_theme_load)(const char*, int, struct wl_shm*); typedef void (* PFN_wl_cursor_theme_destroy)(struct wl_cursor_theme*); typedef struct wl_cursor* (* PFN_wl_cursor_theme_get_cursor)(struct wl_cursor_theme*, const char*); diff --git a/src/wl_window.c b/src/wl_window.c index 1bb32f5f0..ad39b2e0e 100644 --- a/src/wl_window.c +++ b/src/wl_window.c @@ -1413,7 +1413,7 @@ static void handleEvents(double* timeout) if (read(_glfw.wl.keyRepeatTimerfd, &repeats, sizeof(repeats)) == 8) { - if(_glfw.wl.keyboardFocus) + if (_glfw.wl.keyboardFocus) { for (uint64_t i = 0; i < repeats; i++) { @@ -1692,7 +1692,8 @@ static void keyboardHandleKeymap(void* userData, } mapStr = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); - if (mapStr == MAP_FAILED) { + if (mapStr == MAP_FAILED) + { close(fd); return; } @@ -1838,7 +1839,9 @@ static void keyboardHandleKey(void* userData, timer.it_value.tv_nsec = (_glfw.wl.keyRepeatDelay % 1000) * 1000000; timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL); } - } else if (scancode == _glfw.wl.keyRepeatScancode) { + } + else if (scancode == _glfw.wl.keyRepeatScancode) + { timerfd_settime(_glfw.wl.keyRepeatTimerfd, 0, &timer, NULL); } diff --git a/src/x11_monitor.c b/src/x11_monitor.c index 74c57ed01..abf9cbff5 100644 --- a/src/x11_monitor.c +++ b/src/x11_monitor.c @@ -151,7 +151,8 @@ void _glfwPollMonitorsX11(void) } XRRCrtcInfo* ci = XRRGetCrtcInfo(_glfw.x11.display, sr, oi->crtc); - if (!ci) { + if (!ci) + { XRRFreeOutputInfo(oi); continue; } diff --git a/src/x11_window.c b/src/x11_window.c index 02c4ab58d..045878aa5 100644 --- a/src/x11_window.c +++ b/src/x11_window.c @@ -2207,10 +2207,10 @@ void _glfwGetWindowSizeX11(_GLFWwindow* window, int* width, int* height) void _glfwSetWindowSizeX11(_GLFWwindow* window, int width, int height) { - // The dimensions must be nonzero, or a BadValue error results. + // The dimensions must be nonzero, or a BadValue error results width = _glfw_max(1, width); height = _glfw_max(1, height); - + if (window->monitor) { if (window->monitor->window == window)