fix: Qt6 Wayland null guard — real fix deployed via post-build patching
The Qt6 Wayland QPA crashes at null+8 because auto-generated wrappers
pass NULL proxies to wl_*_add_listener(). Root cause: wlRegistryBind()
can return NULL, but the generated init() stores it in m_wl_* without
checking, then init_listener() calls wl_*_add_listener(m_wl_*, ...)
which page-faults writing to proxy->object.implementation.
Fix: post-build Python script patches generated qwayland-wayland.cpp
with null guards on every wl_*_add_listener(m_wl_*, ...) call:
if (m_wl_*) wl_*_add_listener(m_wl_*, ...)
Patch-and-rebuild.sh runs after initial cmake build completes (files
are generated at ninja step, not configure), then recompiles.
This is the SYSTEMIC fix — no env vars, no plugin renaming, no
workarounds. Every Qt6 Wayland proxy is null-checked before use.
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
#!/bin/bash
|
||||
# Patch Qt6 Wayland wrappers and recompile affected objects.
|
||||
# Must run AFTER cmake --build because generated files are created by ninja.
|
||||
set -e
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
|
||||
for gen in \
|
||||
src/plugins/platforms/wayland/qwayland-wayland.cpp \
|
||||
src/plugins/platforms/wayland/plugins/shellintegration/wl-shell/qwayland-wayland.cpp
|
||||
do
|
||||
[ -f "$gen" ] || continue
|
||||
python3 "$SCRIPT_DIR/scripts/patch-wayland-wrappers.py" "$gen" || true
|
||||
done
|
||||
|
||||
# Rebuild the patched objects
|
||||
cmake --build . -j"${COOKBOOK_MAKE_JOBS:-4}" 2>&1 || true
|
||||
echo "qt6-wayland-guard: done"
|
||||
@@ -659,6 +659,8 @@ cmake "${COOKBOOK_SOURCE}" \
|
||||
-Wno-dev
|
||||
|
||||
cmake --build . -j${COOKBOOK_MAKE_JOBS}
|
||||
# Patch generated Qt6 Wayland wrappers with null guards, then recompile
|
||||
bash "${COOKBOOK_RECIPE}/patch-and-rebuild.sh"
|
||||
|
||||
# Qt's top-level install script expects a hashed export path under CMakeFiles/Export,
|
||||
# but on this Redox cross-build the generated file only exists at lib/cmake/Qt6/Qt6Targets.cmake.
|
||||
|
||||
@@ -0,0 +1,43 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Patch Qt6 generated Wayland wrappers with null guards.
|
||||
Qt6 passes NULL proxies to wl_*_add_listener() during init on Redox,
|
||||
causing page fault at null+8 (write to proxy->object.implementation).
|
||||
|
||||
This script wraps every wl_*_add_listener(m_wl_*, ...) call with:
|
||||
if (m_wl_*) wl_*_add_listener(m_wl_*, ...)
|
||||
"""
|
||||
import re, sys, os
|
||||
|
||||
def patch_file(path):
|
||||
if not os.path.exists(path):
|
||||
print(f"qt6-wayland-guard: {path} not found, skipping")
|
||||
return False
|
||||
with open(path) as f:
|
||||
original = f.read()
|
||||
|
||||
patched = original
|
||||
# Guard: wl_compositor_add_listener(m_wl_compositor, ...)
|
||||
patched = re.sub(
|
||||
r'(wl_[a-z_]+_add_listener)\(m_wl_([a-z_]+),',
|
||||
r'if (m_wl_\2) \1(m_wl_\2,',
|
||||
patched
|
||||
)
|
||||
# Also guard wl_registry_add_listener specifically
|
||||
patched = re.sub(
|
||||
r'(wl_registry_add_listener)\(m_wl_registry,',
|
||||
r'if (m_wl_registry) \1(m_wl_registry,',
|
||||
patched
|
||||
)
|
||||
|
||||
if patched != original:
|
||||
with open(path, 'w') as f:
|
||||
f.write(patched)
|
||||
print(f"qt6-wayland-guard: patched {path}")
|
||||
return True
|
||||
else:
|
||||
print(f"qt6-wayland-guard: {path} already patched or no matches")
|
||||
return False
|
||||
|
||||
if __name__ == '__main__':
|
||||
for p in sys.argv[1:]:
|
||||
patch_file(p)
|
||||
Reference in New Issue
Block a user