Phases A-C static diagnosis of the wl_proxy_add_listener null+8 crash. Evidence-backed root cause, candidate patch verdict, ruled-out hypothesis cross-check, and a copy-pasteable instrumented-rebuild runbook for the orchestrator. Verdict: candidate patch qtwaylandscanner-null-guard-listeners.patch guards the CORRECT site (every generated init_listener). Necessary but not sufficient alone — complementary to libwayland redox.patch hunk 1. v5.5 'verified FIXED' claim overstated: never tested in isolation, kded6 workaround masked it, stale-sysroot risk documented.
25 KiB
Qt6 Wayland wl_proxy_add_listener null+8 Crash — Static Diagnosis (Phases A–C)
Status: STATIC DIAGNOSIS COMPLETE. Patch verdict issued. Instrumented-rebuild runbook below for the orchestrator to execute (Phase A instrumentation + forced rebuild chain + QEMU observation). No QEMU runs or multi-hour Qt rebuilds were performed in this diagnosis pass — host contention constraints honoured.
Date: 2026-07-20
Branch: 0.3.1
Scope: Phases A–C of WAYLAND-IMPLEMENTATION-PLAN.md § "Current Blocker"
1. VERDICT (root cause statement)
The NULL proxy at the crash is the wl_registry* returned by
wl_display_get_registry(mDisplay) in
QWaylandDisplay::setupConnection() (qwaylanddisplay.cpp:340), and the crash
site is the qtwaylandscanner-generated QtWayland::wl_registry::init_listener()
calling wl_registry_add_listener(NULL, ...) → wl_proxy_add_listener(NULL, ...)
→ proxy->object.implementation = listener faulting at address 0x8.
A secondary, alternative crash site (consistent with the commit-message root
cause but NOT with the "before any compositor events" signature) is any
generated init_listener() for a global bound via wlRegistryBind() during
QWaylandDisplay::registry_global() (qwaylanddisplay.cpp:634).
The candidate patch
(local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch) guards
both sites because it modifies the code generator to emit
if (m_<iface>) <iface>_add_listener(...) for every generated
init_listener().
Patch verdict: the candidate patch guards the CORRECT site. It is necessary but not sufficient alone — see §4.
2. EVIDENCE CHAIN (every claim cites file:line)
2.1 Crash signature confirmation
| Claim | Evidence |
|---|---|
Fault address 0x8 = write to proxy->object.implementation |
local/recipes/wayland/libwayland/source/src/wayland-client.c:665 — proxy->object.implementation = implementation; |
wl_object.implementation is at offset 8 |
local/recipes/wayland/libwayland/source/src/wayland-private.h:70-74 — struct wl_object { const struct wl_interface *interface; /* off 0 */ const void *implementation; /* off 8 */ uint32_t id; /* off 16 */ }; |
wl_proxy.object is at offset 0 |
local/recipes/wayland/libwayland/source/src/wayland-client.c:63-74 — struct wl_proxy { struct wl_object object; ... }; (first member) |
Therefore proxy==NULL faults at NULL+8 on the implementation write |
Confirmed: *(uintptr_t*)((char*)NULL + 8) = listener = SIGSEGV at 0x8 |
2.2 Qt6 client init sequence (where the first add_listener fires)
Qt 6.11.1 ships the entire Wayland QPA client plugin inside qtbase (not qtwayland). Confirmed locations:
| File | Role |
|---|---|
local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddisplay.cpp |
QWaylandDisplay (the main client-side display object) |
local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddisplay_p.h:105 |
class QWaylandDisplay : public QObject, public QtWayland::wl_registry — QWaylandDisplay IS-A wl_registry wrapper |
local/recipes/qt/qtbase/source/src/tools/qtwaylandscanner/qtwaylandscanner.cpp |
The code generator (vendored into qtbase, not qtwayland) |
Init sequence (qwaylanddisplay.cpp):
Line 322: QWaylandDisplay::QWaylandDisplay(...)
Line 327: mDisplay = wl_display_connect(nullptr);
Line 328: if (mDisplay) { ← rules out NULL display
Line 329: setupConnection();
Line 330: }
Line 338: void QWaylandDisplay::setupConnection()
Line 340: struct ::wl_registry *registry = wl_display_get_registry(mDisplay); ← CAN return NULL
Line 341: init(registry); ← calls generated QtWayland::wl_registry::init(wl_registry*)
The generated init(obj) (qtwaylandscanner.cpp:1155-1160):
void wl_registry::init(struct ::wl_registry *obj)
{
m_wl_registry = obj; // line 1157 — assigned BEFORE init_listener
if (hasEvents)
init_listener(); // line 1159 — called AFTER assignment
}
The generated init_listener() (qtwaylandscanner.cpp:1295-1298, PATCHED):
void wl_registry::init_listener()
{
if (m_wl_registry) wl_registry_add_listener(m_wl_registry, &m_wl_registry_listener, this);
}
Therefore: if wl_display_get_registry() returns NULL → m_wl_registry = NULL
→ patched init_listener() skips the add_listener call → no crash.
Unpatched (upstream Qt 6.11.1) → wl_registry_add_listener(NULL, ...) →
wl_proxy_add_listener(NULL, ...) → page fault at 0x8.
2.3 Why wl_display_get_registry() can return NULL
wl_display_get_registry() is generated code (see
local/recipes/wayland/libwayland/source/tests/data/example-client.h:1027-1036):
static inline struct wl_registry *
wl_display_get_registry(struct wl_display *wl_display)
{
struct wl_proxy *registry;
registry = wl_proxy_marshal_flags((struct wl_proxy *) wl_display,
WL_DISPLAY_GET_REGISTRY, &wl_registry_interface, ...);
return (struct wl_registry *) registry; // NULL if marshal_flags returns NULL
}
wl_proxy_marshal_flags → wl_proxy_marshal_array_flags
(wayland-client.c:901-963) returns NULL when:
| Condition | Source |
|---|---|
create_outgoing_proxy() → proxy_create() OOM (zalloc fails) |
wayland-client.c:487 |
wl_map_insert_new returns 0 (client ID space exhausted) |
wayland-client.c:496-499 |
display->last_error already set (fatal display error) |
wayland-client.c:922-924 |
The third condition is the most plausible: if the implicit display handshake
during wl_display_connect() encounters a protocol or socket error,
display->last_error is set, and the subsequent wl_display_get_registry()
silently returns NULL without even attempting proxy creation.
2.4 Candidate patch guards the correct site
The candidate patch (local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch)
modifies the generator at qtwaylandscanner.cpp:1297 to emit
if (m_%s) %s_add_listener(...) instead of %s_add_listener(...).
This single generator change guards the init_listener() of every generated
Wayland wrapper class — wl_registry, wl_compositor, wl_shm, wl_seat,
wl_output, xdg_wm_base, and all zwp_*/wp_* extensions.
The patch is:
- Confirmed applied to the live source tree (
qtwaylandscanner.cpp:1297shows the patched 4-argument printf). - Confirmed wired in
local/recipes/qt/qtbase/recipe.tomlpatches list (line 14:"qtwaylandscanner-null-guard-listeners.patch"). - Confirmed applicable to Qt 6.11.1 (context lines match; 3-arg → 4-arg printf transformation is unique).
2.5 Complementary guard already in libwayland
A second, independent NULL guard exists in
local/patches/libwayland/redox.patch (added 2026-05-06 in commit
ea125b0b45), which modifies wl_proxy_add_listener itself
(wayland-client.c:652-656):
if (!proxy) {
fprintf(stderr, "FATAL: wl_proxy_add_listener(NULL) caller=%p -- returning error\n",
__builtin_return_address(0));
return -1;
}
This converts the page fault into a logged error + return -1. If this guard
is active, the null+8 page fault CANNOT occur — instead you see the FATAL log
line. The presence of the page-fault crash signature therefore implies the
libwayland guard was not yet compiled into the running binary at the time of
observation (stale libwayland in qtbase's sysroot — see §6).
The two guards are complementary, not redundant in purpose:
- qtwaylandscanner patch: prevents Qt from calling
wl_*_add_listener(NULL)(clean — Qt proceeds with a no-op listener) - libwayland guard: prevents the crash if any caller (Qt or otherwise) passes NULL (defensive — logs + returns error, caller may misbehave)
Neither guard addresses the root cause: why proxy creation returns NULL.
3. CROSS-CHECK OF THE FOUR RULED-OUT HYPOTHESES
| # | Hypothesis | Plan's Verdict | Re-evaluation | Evidence |
|---|---|---|---|---|
| 1 | relibc calloc doesn't zero |
FALSE | SOUND | local/sources/relibc/src/header/stdlib/mod.rs:281 — ptr.write_bytes(0, size) runs unconditionally on every successful malloc. Overflow path returns NULL + ENOMEM (line 287-288). Verified. |
| 2 | Compositor protocol bug | FALSE | SOUND | Compositor is pure-Rust (redbear-compositor), protocol-compliant, doesn't crash. Client crashes during its own init. |
| 3 | wl_display_connect() returns NULL |
FALSE | SOUND | qwaylanddisplay.cpp:327-329 — Qt checks if (mDisplay) before calling setupConnection(). A NULL display never reaches get_registry. |
| 4 | wl_display_get_registry() returns NULL |
FALSE | PARTIALLY UNSOUND — the plan claims "My null guard if (!registry) _exit(1) catches this", but NO such guard exists at qwaylanddisplay.cpp:340-341. The code is struct ::wl_registry *registry = wl_display_get_registry(mDisplay); init(registry); — unconditional. The hypothesis is only effectively ruled out because the candidate patch's init_listener() guard implicitly handles NULL. Without the patch, this is the leading crash cause. |
|
| 5 | libwayland proxy_create() returns NULL |
UNLIKELY | WEAKENED — the plan says "Qt would catch NULL", but Qt does NOT check wlRegistryBind() / wl_display_get_registry() return values. That's exactly the gap the candidate patch closes. The hypothesis is plausible, not unlikely. |
Net effect: hypotheses 1–3 are soundly ruled out. Hypothesis 4's cited
evidence (explicit _exit guard) does not exist in the source — the ruling
holds only because of the candidate patch. Hypothesis 5 is under-weighted:
NULL returns from proxy creation are not caught by Qt without the patch.
4. PATCH VERDICT
Candidate: local/patches/qtbase/qtwaylandscanner-null-guard-listeners.patch
Verdict: CORRECT SITE, NECESSARY, BUT NOT SUFFICIENT ALONE.
| Question | Answer |
|---|---|
Does the crash happen inside scanner-generated init_listener()? |
YES — wl_proxy_add_listener is only reachable from wl_*_add_listener wrappers, which in Qt's client init path are only emitted by qtwaylandscanner inside init_listener(). The hand-written wl_callback_add_listener / wl_buffer_add_listener sites (see §5) all fire LATER, after the first roundtrip. |
| Does the patch guard the actual crash site? | YES — the generator change emits if (m_<iface>) before every wl_*_add_listener(m_<iface>, ...) in every generated init_listener(). |
Is the patch the same as upstream commits de2d74c37e/882c2974ec? |
de2d74c37e/882c2974ec ARE the Red Bear commits that introduced this patch. They are not upstream Qt commits. de2d74c37e (2026-05-06 17:18) made the direct source edit; 882c2974ec (2026-05-07) extracted it into the patch file + wired recipe.toml. |
| Was the patch runtime-validated? | NO — not in isolation. Commit de2d74c37e claims "VERIFIED: greeter UI boots", but this was done with THREE fixes simultaneously applied (qtwaylandscanner patch + libwayland NULL guard from ea125b0b45 13:44 same day + kded6 workaround renaming libqwayland.so to .disabled). The qtwaylandscanner patch alone was never proven. The "7 globals" claim in the commit message also disagrees with the compositor's actual 8 globals, suggesting incomplete observation. |
| Is a corrected patch needed? | NO for the reported crash. The candidate guards the correct site. Additional hardening for non-scanner sites is recommended (§5) but is a separate concern. |
Why "not sufficient alone"
The patch prevents Qt from calling wl_*_add_listener(NULL), but it does NOT
fix the root cause: why wl_display_get_registry() or wlRegistryBind()
returns NULL in the first place. With the patch applied, Qt silently proceeds
with m_wl_registry == nullptr, the registry listener is never attached, Qt
receives no global announcements, and the desktop session fails to initialise
(no screens, no compositor, no input devices) — a different failure mode than a
page fault, but still a non-functional desktop.
The root cause requires Phase A instrumentation + Phase C libwayland audit to
determine which of the three NULL-return paths (OOM, map exhaustion, or
display->last_error) is firing.
Relationship to existing patches
| Patch | Location | Status | Relationship |
|---|---|---|---|
qtwaylandscanner-null-guard-listeners.patch |
local/patches/qtbase/ |
Candidate (this diagnosis) | Generator-level guard — prevents the call |
libwayland redox.patch hunk 1 |
local/patches/libwayland/redox.patch |
Applied (commit ea125b0b45) |
Library-level guard — prevents the crash if call happens |
patch-wayland-gen.sh |
local/recipes/qt/qtbase/ |
ORPHANED — never invoked from recipe.toml | Legacy sed-based post-build patcher (replaced by the generator patch) |
qtwayland-empty-cursor-guards.patch |
local/recipes/qt/qtbase/ |
ORPHANED — not in recipe.toml patches list | Unrelated (cursor theme empty-image guards) |
P0-fix-broken-include.patch, P1-qplatformopengl-guard.patch |
local/patches/qtbase/ |
ORPHANED — symlinks exist in recipe dir but not in patches list | Not applied to current builds |
No file changes are needed to the candidate patch. It is correct. The runbook below (§7) validates it end-to-end.
5. UNGUARDED add_listener SITES (hardening recommendations — NOT the crash site)
These hand-written wl_*_add_listener calls are NOT guarded by the candidate
patch (which only covers scanner-generated code). All fire AFTER the first
roundtrip, so they are NOT the "before any compositor events" crash site. Listed
for completeness; a separate hardening patch could address them:
| File:Line | Call | When it fires |
|---|---|---|
qwaylanddisplay.cpp:1049 |
wl_callback_add_listener(mSyncCallback, &syncCallbackListener, this) |
requestWaylandSync() — during sync/roundtrip |
qwaylandbuffer.cpp:27 |
wl_buffer_add_listener(buf, &listener, this) |
Buffer creation — during surface commit |
qwaylandwindow.cpp:1807 |
wl_callback_add_listener(mFrameCallback, &callbackListener, this) |
Frame callback — during surface render |
qwaylandtextinputv2.cpp:178 |
wl_callback_add_listener(m_resetCallback, &callbackListener, this) |
Text input reset — during IME interaction |
qwaylandbrcmeglwindow.cpp:50 |
wl_buffer_add_listener(mBuffer, &buffer_listener, this) |
Broadcom EGL — hardware integration (not loaded on Redox) |
These are all covered by the libwayland-level NULL guard (redox.patch hunk 1),
so they will log FATAL + return -1 rather than crash. A future hardening patch
to Qt would add explicit if (ptr) checks at each site for cleaner diagnostics.
6. WHY THE CRASH PERSISTED DESPITE "VERIFIED FIXED" (May 2026)
The v5.5 changelog (CONSOLE-TO-KDE-DESKTOP-PLAN.md:38-46) and four other
locations claim the crash is "verified FIXED" via commits de2d74c37e +
882c2974ec. This claim is overstated for three reasons:
-
Never tested in isolation. The May 6 verification had three fixes applied simultaneously. The qtwaylandscanner patch was never proven to fix the crash on its own.
-
The kded6 workaround masked it. Commit
176624a008(2026-05-06 16:34, one hour beforede2d74c37e) deployed a wrapper script that renameslibqwayland.soto.disabledbefore launching kded6, preventing Qt from loading the Wayland plugin at all. The "greeter UI boots" verification may have been of a greeter running WITHOUT the Wayland plugin (offscreen QPA), not WITH the patched Wayland plugin. -
Stale-sysroot rebuild chain. The
WAYLAND-IMPLEMENTATION-PLAN.md:157-171documents that "Modifying only libwayland does NOT update qtbase's static copy oflibwayland-client.a. The old binary persists in qtbase's sysroot." If the full chain (libwayland → qtbase → qtdeclarative → qtwayland) was not force-rebuilt, the running binary may have linked against an unpatched libwayland, making the page fault reappear.
The crash re-appears as the active blocker in WAYLAND-IMPLEMENTATION-PLAN.md
(dated 2026-07-08, two months after the "fix") and
CONSOLE-TO-KDE-DESKTOP-PLAN.md:234 (2026-06-20, "WIRED, UNVALIDATED"). The
"verified FIXED" line at CONSOLE-TO-KDE-DESKTOP-PLAN.md:43 directly
contradicts line 240-243 of the same document.
The v5.5 claim should be corrected to "WIRED, NEVER RUNTIME-VALIDATED IN ISOLATION" until the Phase A runbook below produces positive QEMU evidence.
7. INSTRUMENTED-REBUILD RUNBOOK (Phase A diagnostics + forced chain)
This runbook is for the orchestrator to execute when host contention allows. It produces definitive evidence of WHICH proxy is NULL and WHY.
7.1 Phase A: Add fprintf diagnostics (3 files)
All edits are to the live source trees. They will be discarded on next
repo fetch, so mirror them into patches if durability is needed.
Edit 1: local/recipes/qt/qtbase/source/src/plugins/platforms/wayland/qwaylanddisplay.cpp
In setupConnection() (around line 340), add:
void QWaylandDisplay::setupConnection()
{
struct ::wl_registry *registry = wl_display_get_registry(mDisplay);
fprintf(stderr, "[RB-DIAG] setupConnection: mDisplay=%p registry=%p\n", (void*)mDisplay, (void*)registry);
init(registry);
fprintf(stderr, "[RB-DIAG] setupConnection: init() returned, m_wl_registry=%p\n", (void*)object());
Edit 2: local/recipes/qt/qtbase/source/src/tools/qtwaylandscanner/qtwaylandscanner.cpp
In the init_listener() generator (around line 1295), add a diagnostic printf
INSIDE the generated function. Change the patched line to:
printf(" fprintf(stderr, \"[RB-DIAG] init_listener m_%s=%p\\n\", (void*)m_%s);\n", interfaceName, interfaceName);
printf(" if (m_%s) %s_add_listener(m_%s, &m_%s_listener, this);\n", interfaceName, interfaceName, interfaceName, interfaceName);
printf(" else fprintf(stderr, \"[RB-DIAG] SKIPPED add_listener for %s (NULL proxy)\\n\");\n", interfaceName);
Edit 3: local/recipes/wayland/libwayland/source/src/wayland-client.c
In wl_proxy_marshal_array_flags (around line 920), add before the
display->last_error check:
if (display->last_error)
fprintf(stderr, "[RB-DIAG] marshal_flags: display->last_error=%d, opcode=%u\n",
display->last_error, opcode);
And in proxy_create (around line 487), add:
if (proxy == NULL) {
fprintf(stderr, "[RB-DIAG] proxy_create: zalloc FAILED (OOM)\n");
return NULL;
}
7.2 Phase B: Force-rebuild chain (in strict order)
The chain MUST be rebuilt in this order. Skipping any step leaves a stale binary in the next recipe's sysroot.
# Step 0: Rebuild prefix (relibc headers if Phase A edit 3 touched wayland-client.c)
touch relibc && make prefix
# Step 1: Force-rebuild libwayland (Phase A edit 3)
rm -rf local/recipes/wayland/libwayland/target
rm -f repo/x86_64-unknown-redox/libwayland.pkgar
./target/release/repo cook libwayland --force-rebuild
# Step 2: Force-rebuild qtbase (Phase A edits 1 + 2; picks up new libwayland)
rm -rf local/recipes/qt/qtbase/target
rm -f repo/x86_64-unknown-redox/qtbase.pkgar
./target/release/repo cook qtbase --force-rebuild
# Step 3: Force-rebuild qtdeclarative (links against new qtbase)
rm -rf local/recipes/qt/qtdeclarative/target
rm -f repo/x86_64-unknown-redox/qtdeclarative.pkgar
./target/release/repo cook qtdeclarative --force-rebuild
# Step 4: Force-rebuild qtwayland (uses qtwaylandscanner from new qtbase)
rm -rf local/recipes/qt/qtwayland/target
rm -f repo/x86_64-unknown-redox/qtwayland.pkgar
./target/release/repo cook qtwayland --force-rebuild
# Step 5: Rebuild the full image
./local/scripts/build-redbear.sh redbear-full
If repo cook is unavailable, use make r.<recipe> + make cr.<recipe>
(clean + rebuild) equivalents.
7.3 Phase C: QEMU invocation + serial-log markers
# Boot the instrumented image with serial console captured
qemu-system-x86_64 \
-cdrom build/x86_64/redbear-full.iso \
-m 4096 \
-serial file:/tmp/rb-wayland-diag.log \
-netdev user,id=n0 -device e1000,netdev=n0 \
-display none \
2>&1 | tee /tmp/rb-qemu-stdout.log
# After boot, trigger a Wayland client (greeter or smoke test)
# Inside the guest (via serial console):
# export QT_QPA_PLATFORM=wayland
# export WAYLAND_DISPLAY=wayland-0
# /usr/lib/qt6/examples/wayland/minimal-qml # or any Qt6 Wayland client
7.4 Markers to observe in /tmp/rb-wayland-diag.log
| Marker | Meaning | Action |
|---|---|---|
[RB-DIAG] setupConnection: mDisplay=0x... registry=0x... |
Connection established; check if registry is NULL | If registry=(nil), root cause is in wl_display_get_registry |
[RB-DIAG] setupConnection: init() returned, m_wl_registry=0x... |
Registry wrapper initialised | If (nil), the patched init_listener skipped |
[RB-DIAG] init_listener m_wl_registry=0x... |
Generated init_listener executed for wl_registry | Confirms the scanner-generated code runs |
[RB-DIAG] SKIPPED add_listener for wl_registry (NULL proxy) |
The candidate patch fired — NULL was caught | Patch works. Root cause is upstream (proxy creation). |
[RB-DIAG] marshal_flags: display->last_error=N |
Display had a prior fatal error | Root cause: display handshake failure. Investigate socket/IPC. |
[RB-DIAG] proxy_create: zalloc FAILED (OOM) |
Out of memory during proxy allocation | Root cause: OOM. Increase guest RAM or audit relibc allocator. |
FATAL: wl_proxy_add_listener(NULL) caller=0x... |
libwayland guard fired (some caller passed NULL) | The candidate patch did NOT catch this site — the NULL came from a non-scanner call site (§5). Use addr2line on the caller address. |
Page fault: 0000000000000008 US |
The crash persisted — BOTH guards failed to apply | Stale binary in sysroot. Re-run the forced rebuild chain. |
7.5 Decision tree after observation
Observe the FIRST [RB-DIAG] or crash marker:
├── registry=(nil) in setupConnection
│ ├── display->last_error set → ROOT CAUSE: display handshake failure (IPC/socket)
│ ├── zalloc FAILED → ROOT CAUSE: OOM in proxy_create
│ └── neither → ROOT CAUSE: wl_map_insert_new returned 0 (investigate)
│
├── registry=0x... (non-NULL) but SKIPPED add_listener
│ └── Patch works; root cause is elsewhere in global binding (registry_global path)
│
├── FATAL: wl_proxy_add_listener(NULL) caller=0x...
│ └── addr2line -e <binary> <caller_addr> → identifies the exact unguarded call site (§5)
│
└── Page fault at 0x8 (no markers)
└── Stale binary — repeat forced rebuild chain with --no-cache
8. SUMMARY TABLE
| Question | Answer |
|---|---|
| Which proxy is NULL? | wl_registry* from wl_display_get_registry() (primary) or any wl_<iface>* from wlRegistryBind() (secondary) |
| Why is it NULL? | wl_proxy_marshal_array_flags returns NULL: OOM, map exhaustion, or display->last_error set |
| Where is the crash? | Generated init_listener() → wl_*_add_listener(NULL) → wl_proxy_add_listener(NULL) → proxy->object.implementation = listener at wayland-client.c:665 |
| Does the patch guard the crash site? | YES — qtwaylandscanner.cpp:1297 emits if (m_<iface>) before every generated add_listener |
| Is the patch sufficient alone? | NO — prevents crash but not the root cause (NULL proxy creation); also redundant with libwayland redox.patch hunk 1 |
| Is a corrected patch needed? | NO — the candidate is correct for the reported crash |
| Was the v5.5 "verified FIXED" sound? | NO — never tested in isolation; kded6 workaround masked it; stale-sysroot risk |
| Are the ruled-out hypotheses sound? | Hypotheses 1–3 sound; 4 cites non-existent evidence; 5 is under-weighted |
9. FILES CHANGED IN THIS DIAGNOSIS
| File | Change |
|---|---|
local/docs/QT6-WAYLAND-NULL8-DIAGNOSIS.md |
NEW — this report |
local/patches/qtbase/ |
No changes — candidate patch is correct |
local/recipes/qt/qtbase/recipe.toml |
No changes — patch is already wired (line 14) |
10. NEXT STEPS (for the orchestrator)
- Execute the Phase A runbook (§7) when host contention allows. The fprintf diagnostics will definitively identify which NULL-return path fires.
- Do NOT remove the candidate patch — it is correct and necessary.
- Do NOT trust the "verified FIXED" claims in
CONSOLE-TO-KDE-DESKTOP-PLAN.md:43,config/redbear-full.toml:183,local/recipes/kde/kwin/recipe.toml:2, orlocal/docs/archived/IMPLEMENTATION-MASTER-PLAN.md:61until positive QEMU evidence from §7.4 confirms the crash is gone. - If the runbook reveals
display->last_erroras the root cause, the fix is in the IPC/socket layer (kernel or relibc), not in Qt or libwayland. - If the runbook reveals OOM, increase guest RAM or audit the relibc
allocator (
dlmalloc) for fragmentation under Qt6's allocation pattern.