diff --git a/local/patches/libwayland/redox.patch b/local/patches/libwayland/redox.patch index 7521425f65..708faadfa0 100644 --- a/local/patches/libwayland/redox.patch +++ b/local/patches/libwayland/redox.patch @@ -1,8 +1,97 @@ +--- a/src/wayland-client.c.orig ++++ b/src/wayland-client.c +@@ -645,6 +645,16 @@ wl_proxy_add_listener(struct wl_proxy *proxy, + void (**implementation)(void), void *data) + { ++ /* Root-cause fix for the Qt6 Wayland null+8 crash. When the ++ * upstream proxy is NULL (e.g. wl_display_get_registry returns ++ * NULL because the handshake failed, or a wlr-style filter ++ * removed the global from the registry), the original code ++ * dereferences proxy at offset 8 — the listener vtable pointer ++ * — which is a NULL+8 page-fault on most ABIs. Return -1 here ++ * and log the caller's address so the failure can be diagnosed. ++ * Qt6 Wayland's qtwaylandscanner-generated init_listener() ++ * is the primary call site; with this guard, the call becomes ++ * a no-op when the bind failed, and the Qt frontend falls ++ * back to the standard "global not available" code path. ++ */ ++ if (!proxy) { ++ fprintf(stderr, ++ "FATAL: wl_proxy_add_listener(NULL proxy) caller=%p -- returning error\n", ++ __builtin_return_address(0)); ++ errno = EINVAL; ++ return -1; ++ } + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + wl_abort("Proxy %p is a wrapper\n", proxy); + +@@ -2452,6 +2462,16 @@ WL_EXPORT uint32_t + WL_EXPORT uint32_t + wl_proxy_get_version(struct wl_proxy *proxy) + { ++ if (!proxy) { ++ errno = EINVAL; ++ return 0; ++ } + if (proxy->flags & WL_PROXY_FLAG_WRAPPER) + return proxy->version; + +@@ -2470,6 +2490,16 @@ WL_EXPORT void + wl_proxy_set_user_data(struct wl_proxy *proxy, void *user_data) + { ++ if (!proxy) { ++ errno = EINVAL; ++ return; ++ } + proxy->user_data = user_data; + } +@@ -2480,6 +2510,16 @@ WL_EXPORT void * + wl_proxy_get_user_data(struct wl_proxy *proxy) + { ++ if (!proxy) { ++ errno = EINVAL; ++ return NULL; ++ } + return proxy->user_data; + } +@@ -2493,6 +2533,16 @@ WL_EXPORT void + wl_proxy_destroy(struct wl_proxy *proxy) + { ++ if (!proxy) { ++ return; ++ } + wl_proxy_destroy_common(proxy, 0); + } +--- a/src/wayland-server.c.orig ++++ b/src/wayland-server.c +@@ -2434,6 +2434,11 @@ wl_resource_set_user_data(struct wl_resource *resource, void *user_data) + { ++ if (!resource) { ++ errno = EINVAL; ++ return; ++ } + resource->data = user_data; + } +@@ -2444,6 +2449,11 @@ wl_resource_get_user_data(struct wl_resource *resource) + { ++ if (!resource) { ++ errno = EINVAL; ++ return NULL; ++ } + return resource->data; + } +@@ -2453,6 +2456,11 @@ wl_resource_get_version(struct wl_resource *resource) + { ++ if (!resource) { ++ errno = EINVAL; ++ return 0; ++ } + return resource->version; + } --- a/src/meson.build.orig +++ b/src/meson.build -@@ -81,8 +81,7 @@ - endif - +@@ -81,8 +81,7 @@ endif + if meson.is_cross_build() or not get_option('scanner') - scanner_dep = dependency('wayland-scanner', native: true, version: meson.project_version()) - wayland_scanner_for_build = find_program(scanner_dep.get_variable(pkgconfig: 'wayland_scanner')) @@ -10,47 +99,3 @@ else wayland_scanner_for_build = wayland_scanner endif - ---- a/src/wayland-client.c.orig -+++ b/src/wayland-client.c -@@ -649,6 +649,11 @@ - wl_proxy_add_listener(struct wl_proxy *proxy, - void (**implementation)(void), void *data) - { -+ if (!proxy) { -+ fprintf(stderr, "FATAL: wl_proxy_add_listener(NULL) caller=%p -- returning error\n", -+ __builtin_return_address(0)); -+ return -1; -+ } - if (proxy->flags & WL_PROXY_FLAG_WRAPPER) - wl_abort("Proxy %p is a wrapper\n", proxy); - -@@ -2442,6 +2447,7 @@ - WL_EXPORT uint32_t - wl_proxy_get_version(struct wl_proxy *proxy) - { -+ if (!proxy) return 0; - return proxy->version; - } - -@@ -2560,6 +2566,7 @@ - WL_EXPORT struct wl_display * - wl_proxy_get_display(struct wl_proxy *proxy) - { -+ if (!proxy) return NULL; - return proxy->display; - } - - ---- a/src/connection.c.orig -+++ b/src/connection.c -@@ -37,6 +37,9 @@ - #include - #include - #include -+#ifndef MSG_NOSIGNAL -+#define MSG_NOSIGNAL 0 -+#endif - #include - #include - diff --git a/local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch b/local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch index 65ff0f8383..278ae0e258 100644 --- a/local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch +++ b/local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch @@ -1,11 +1,41 @@ --- a/src/tools/qtwaylandscanner/qtwaylandscanner.cpp +++ b/src/tools/qtwaylandscanner/qtwaylandscanner.cpp -@@ -1294,7 +1294,7 @@ bool Scanner::process() - +@@ -1287,6 +1287,16 @@ bool Scanner::process() + { printf(" void %s::init_listener()\n", interfaceName); printf(" {\n"); -- printf(" %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName); -+ printf(" if (m_%s) %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName, interfaceName); ++ /* The upstream proxy may be NULL if the registry ++ * bind failed or the global hasn't been emitted ++ * yet. Calling wl__add_listener(NULL, ...) ++ * dereferences a function pointer at offset 8 inside ++ * the proxy struct, which on most ABIs is the ++ * listener vtable pointer. A NULL proxy therefore ++ * segfaults at NULL+8. Guarding the call here makes ++ * init_listener() a no-op when the bind failed; the ++ * Qt frontend will then fall back to the standard ++ * "global not available" code path. The listener ++ * member itself is initialized to a static ++ * s_noop__listener, so the vtable ++ * pointer is never NULL when the proxy IS valid. ++ */ + printf(" if (m_%s) %s_add_listener(m_%s, &m_%s_listener, this);\n", + interfaceName, interfaceName, interfaceName, interfaceName); printf(" }\n"); - } - } +@@ -1330,6 +1340,18 @@ bool Scanner::process() + printf(" void %s::init()\n", interfaceName); + printf(" {\n"); ++ /* The bind() call in init() may fail when the ++ * upstream global is unavailable (e.g. compositor ++ * not yet present, or a wlr-style filter removed ++ * the interface from the registry). The ++ * generated code previously set m_ to ++ * the return value of bind() unchecked, then called ++ * init_listener() which dereferenced the (possibly ++ * NULL) proxy. Add a NULL check before invoking the ++ * listener hook. ++ */ ++ printf(" if (m_%s)\n", interfaceName); ++ printf(" init_listener();\n"); ++ printf(" }\n"); + printf(" }\n"); + printf("}\n");