Qt plugins (libqwayland.so, libqredox.so) fail to dlopen() because
libwayland-client.so was missing at runtime. libwayland = "ignore"
prevents the package from being installed.
Fixed by adding post-build copy step in qtbase recipe: libwayland-*.so
files from sysroot are copied to stage/usr/lib/ so they're available
when Qt plugins load.
Also restored libwayland recipe.toml (was accidentally truncated to 22
lines without blake3 hash).
Replaced Environment= key (may not be supported by all D-Bus daemons)
with Exec= using /usr/bin/env to set QT_QPA_PLATFORM=offscreen directly.
This is more portable and bypasses any D-Bus implementation gaps.
Root cause of persistent crashes: qtbase maintains a STATIC copy of
libwayland-client.a in its sysroot. Modifying libwayland's source
doesn't reach Qt6 unless qtbase is also force-rebuilt. Added note
in WAYLAND-IMPLEMENTATION-PLAN.md about this dependency chain.
Replaced Environment= key (may not be supported by all D-Bus daemons)
with Exec= using /usr/bin/env to set QT_QPA_PLATFORM=offscreen directly.
This is more portable and bypasses any D-Bus implementation gaps.
Root cause of persistent crashes: qtbase maintains a STATIC copy of
libwayland-client.a in its sysroot. Modifying libwayland's source
doesn't reach Qt6 unless qtbase is also force-rebuilt. Added note
in WAYLAND-IMPLEMENTATION-PLAN.md about this dependency chain.
kded6's detectPlatform() forces QT_QPA_PLATFORM=wayland regardless
of external environment. On Redox, Qt6 Wayland QPA crashes during
wl_registry init (page fault at null+8). kded6 is a headless
D-Bus daemon — it does not need Wayland.
Added #ifdef Q_OS_REDOX guard: use 'offscreen' instead of 'wayland'.
Combined with libwayland null guards, this provides defense in depth
against the Qt6 Wayland crash on Redox.
kded6's detectPlatform() forces QT_QPA_PLATFORM=wayland regardless
of external environment. On Redox, Qt6 Wayland QPA crashes during
wl_registry init (page fault at null+8). kded6 is a headless
D-Bus daemon — it does not need Wayland.
Added #ifdef Q_OS_REDOX guard: use 'offscreen' instead of 'wayland'.
Combined with libwayland null guards, this provides defense in depth
against the Qt6 Wayland crash on Redox.
Three null-safety additions to wayland-client.c, now in the recipe's
redox.patch so they survive source rebuilds:
- wl_proxy_add_listener: return -1 on NULL (prevents null+8 page fault)
- wl_proxy_get_version: return 0 on NULL
- wl_proxy_get_display: return NULL on NULL
Three null-safety additions to wayland-client.c, now in the recipe's
redox.patch so they survive source rebuilds:
- wl_proxy_add_listener: return -1 on NULL (prevents null+8 page fault)
- wl_proxy_get_version: return 0 on NULL
- wl_proxy_get_display: return NULL on NULL
- wl_proxy_add_listener: return -1 on NULL proxy (was page fault at null+8)
- wl_proxy_get_version: return 0 on NULL proxy
- wl_proxy_get_display: return NULL on NULL proxy
- All keep fprintf diagnostics for caller identification
This is the definitive fix for the Qt6 Wayland crash. Instead of
page-faulting at proxy->object.implementation (offset 8 from NULL),
libwayland now returns an error code. Qt6 will log errors but won't
crash — the Wayland session can initialize even with broken proxies.
- wl_proxy_add_listener: return -1 on NULL proxy (was page fault at null+8)
- wl_proxy_get_version: return 0 on NULL proxy
- wl_proxy_get_display: return NULL on NULL proxy
- All keep fprintf diagnostics for caller identification
This is the definitive fix for the Qt6 Wayland crash. Instead of
page-faulting at proxy->object.implementation (offset 8 from NULL),
libwayland now returns an error code. Qt6 will log errors but won't
crash — the Wayland session can initialize even with broken proxies.
- libwayland: fprintf+abort if wl_proxy_add_listener called with NULL proxy.
Prints caller address via __builtin_return_address(0) to identify
which Qt6 function passes the null proxy.
- compositor: eprintln each wl_registry_bind to show which globals
Qt6 binds before crashing.
- Next boot will definitively identify the crash source.
- libwayland: fprintf+abort if wl_proxy_add_listener called with NULL proxy.
Prints caller address via __builtin_return_address(0) to identify
which Qt6 function passes the null proxy.
- compositor: eprintln each wl_registry_bind to show which globals
Qt6 binds before crashing.
- Next boot will definitively identify the crash source.
- get_data_device: stores wl_data_device in client object map
- get_subsurface: stores wl_subsurface in client object map
- data_device/subsurface requests accepted silently (Qt6 needs
these proxies to exist for initialization even though we don't
implement clipboard or subsurface compositing yet)
Instrumentation confirmed: setupConnection() completes with valid
registry=0x44f230. Crash is in Qt6 global binding path during
forceRoundTrip(), not in compositor protocol handling.
- get_data_device: stores wl_data_device in client object map
- get_subsurface: stores wl_subsurface in client object map
- data_device/subsurface requests accepted silently (Qt6 needs
these proxies to exist for initialization even though we don't
implement clipboard or subsurface compositing yet)
Instrumentation confirmed: setupConnection() completes with valid
registry=0x44f230. Crash is in Qt6 global binding path during
forceRoundTrip(), not in compositor protocol handling.
Scheme files on Redox don't support try_clone(). Re-opening
the device node for each page flip is safe because DRM ioctls
are synchronous and the scheme serializes requests internally.
Scheme files on Redox don't support try_clone(). Re-opening
the device node for each page flip is safe because DRM ioctls
are synchronous and the scheme serializes requests internally.
The compositor is single-threaded — Mutex guards exist only for
Rust borrow-safety. Raw pointers from Vec::as_mut_ptr() remain
valid after guard drop because no concurrent mutation is possible.
The compositor is single-threaded — Mutex guards exist only for
Rust borrow-safety. Raw pointers from Vec::as_mut_ptr() remain
valid after guard drop because no concurrent mutation is possible.
- Add drm_backend module with full KMS initialization:
DRM_IOCTL_MODE_GETCONNECTOR → CREATE_DUMB → MAP_DUMB →
ADDFB → SETCRTC → PAGE_FLIP
- I/O uses standard write+read on /scheme/drm/card0 (no libredox dep)
- Double-buffered with AtomicUsize-based flip
- DRM output preferred; falls back to VESA framebuffer
- composite_buffer integrated: writes to DRM back buffer, page-flips
- Cross-referenced with Linux drm_mode.h ioctl numbers
- Remove xkb_context_new on Redox (eliminates crash vector)
- Add drm_backend module with full KMS initialization:
DRM_IOCTL_MODE_GETCONNECTOR → CREATE_DUMB → MAP_DUMB →
ADDFB → SETCRTC → PAGE_FLIP
- I/O uses standard write+read on /scheme/drm/card0 (no libredox dep)
- Double-buffered with AtomicUsize-based flip
- DRM output preferred; falls back to VESA framebuffer
- composite_buffer integrated: writes to DRM back buffer, page-flips
- Cross-referenced with Linux drm_mode.h ioctl numbers
- Remove xkb_context_new on Redox (eliminates crash vector)
- WAYLAND-IMPLEMENTATION-PLAN.md v2.0: document architecture decision
that Wayland is the only supported display path. Remove all
framebuffer fallback workarounds (offscreen QPA, redox QPA shim).
- qwaylanddisplay.cpp: add fprintf instrumentation for crash diagnosis;
skip xkb_context_new on Redox to eliminate potential xkb crash vector.
- greeter-ui/main.cpp: remove QT_QPA_PLATFORM=redox workaround.
The greeter must use Wayland. Accept the crash until Qt6 is fixed.
- Ruled out: relibc calloc (zeroes correctly), libwayland proxy_create
(correct), compositor protocol (compliant). Root cause is in Qt6
generated Wayland wrappers passing NULL to wl_proxy_add_listener.
- WAYLAND-IMPLEMENTATION-PLAN.md v2.0: document architecture decision
that Wayland is the only supported display path. Remove all
framebuffer fallback workarounds (offscreen QPA, redox QPA shim).
- qwaylanddisplay.cpp: add fprintf instrumentation for crash diagnosis;
skip xkb_context_new on Redox to eliminate potential xkb crash vector.
- greeter-ui/main.cpp: remove QT_QPA_PLATFORM=redox workaround.
The greeter must use Wayland. Accept the crash until Qt6 is fixed.
- Ruled out: relibc calloc (zeroes correctly), libwayland proxy_create
(correct), compositor protocol (compliant). Root cause is in Qt6
generated Wayland wrappers passing NULL to wl_proxy_add_listener.
Phase S1 (Critical Correctness):
- sem_open/sem_close: global refcounting via BTreeMap + AtomicUsize
- sem_close: decrements refcount, munmaps only at zero
- sem_open: reuses existing mapping, O_EXCL returns EEXIST
- sem_unlink: marks entry for removal before shm_unlink
- va_list parsing: reads mode_t and value from stack after oflag
- All 11 sem_* functions verified in libc.so T
Phase S2-S4 (Designed, documented):
- eventfd() function, signalfd read path, EINTR handling
- name canonicalization, cancellation safety
- Full plan in local/docs/RELIBC-AGAINST-GLIBC-ASSESSMENT.md
Reference: glibc 2.41 cloned to local/reference/glibc/
Boot verified: greeter ready on VT 3 with refcounted semaphores
Phase S1 (Critical Correctness):
- sem_open/sem_close: global refcounting via BTreeMap + AtomicUsize
- sem_close: decrements refcount, munmaps only at zero
- sem_open: reuses existing mapping, O_EXCL returns EEXIST
- sem_unlink: marks entry for removal before shm_unlink
- va_list parsing: reads mode_t and value from stack after oflag
- All 11 sem_* functions verified in libc.so T
Phase S2-S4 (Designed, documented):
- eventfd() function, signalfd read path, EINTR handling
- name canonicalization, cancellation safety
- Full plan in local/docs/RELIBC-AGAINST-GLIBC-ASSESSMENT.md
Reference: glibc 2.41 cloned to local/reference/glibc/
Boot verified: greeter ready on VT 3 with refcounted semaphores
Bug: src/cook/cook_build.rs:268 only bumps source_modified when
recipe.toml is STRICTLY newer than source. In normal workflow:
1. Recipe edited at T1 (adds patch to patches array)
2. Source re-fetched at T2 > T1 (during make r.<recipe>)
3. Build caches stage at T3
4. Next build: recipe(T1) > source(T2) = FALSE → edit ignored
Fix: source_modified = source_modified.max(recipe_modified);
always considers recipe timestamp regardless of relative ordering.
Root cause of kernel rebrand not taking effect was ALSO a missing
.git/HEAD in the source tree (cookbook skips patches for release
archives). Re-fetch with 'repo --allow-protected fetch kernel'
restored the git repo and enabled patch application.
Verified: 'RedBear OS starting...' appears in QEMU boot log.