Wayland: resolve session lock client crashes on sleep, unlock, and output changes#829
Wayland: resolve session lock client crashes on sleep, unlock, and output changes#829Luke458 wants to merge 6 commits into
Conversation
|
I should also mention that I understand deleteLater() is standard Qt/QML practice and directly deleting a QObject using the C++ delete operator is generally discouraged as the QML engine bindings or event queues might still hold references to the object during the current event loop cycle. However, this usage is safe from a Qt perspective because these surfaces are created and owned purely in C++ by WlSessionLock and are not shared with, referenced by, or garbage-collected through QML bindings elsewhere. |
|
Update: Added a second commit to prevent a crash during sleep/DPMS transitions. When display outputs are temporarily disconnected or in a transition state, updateSurfaces() is now prevented from creating lock surfaces on placeholder or invalid screens. This avoids triggering the qFatal check in the QSWaylandSessionLockSurface constructor. |
|
upon further testing, this is an improvement but it doesn't fully resolve the wake from suspend/dpms off crashing. It prevents all wayland clients from crashing but quickshell itself will still crash :/ |
|
Okay final update (I hope), after the second commit there were still 3 issues remaining. The first issue involved a screen state transition abort caused by a The second issue was a Wayland protocol error: The third issue was another protocol error: |
92a0fdd to
1ea83fc
Compare
|
FINAL FINAL commits this time to fix the last couple of issues. Firstly, just fixed the CI failure with qt 6.6.3 as described in the commit. More importantly, resolved a double-free crash with the error |
|
After extensive debugging and validation, I've identified why this crash may be highly reproducible on systems running The issue is triggered by how quickly the open-source AMD GPU stack handles display power transitions. Unlike some proprietary driver setups(Nvidia), Similarly, Hyprland is extremely strict about Wayland object state and the moment unlock_and_destroy is processed, Hyprland immediately invalidates the surface IDs. If the client sends a destroy or commit on those IDs a split-second later, Hyprland raises a fatal protocol error ( invalid object or Null buffer attached ) and kills the client. This exposes a race condition in Quickshell’s client-side surface lifecycle. If the client calls The final fix resolves this by enforcing a strict teardown order. In After that, the window is destroyed synchronously with The destructor also now begins with an early-return guard, Finally, |
|
AvengeMedia/DankMaterialShell#1468 (comment) Many thanks to @bzbetty for testing and proposing this final change ^^ The original reason for switching to synchronous
The current unlock sequence is:
By the time the deferred deletion from step 2 actually executes, the lock role has already been removed in step 1 and the session has already been unlocked in step 3. As a result, any null-buffer commits generated by Qt's normal window-hide or teardown routines are no longer subject to the restrictions of the |
Under the ext-session-lock-v1 protocol, calling unlock_and_destroy immediately invalidates and destroys all associated lock surface objects on the compositor.
In WlSessionLock::unlock(), the manager was unlocked before deleting the surfaces. Because surface->deleteLater() is asynchronous, the destructors ran in the next event loop tick and sent ext_session_lock_surface_v1.destroy requests to the compositor for object IDs that the compositor had already discarded, leading to a fatal invalid object Wayland protocol error and session crash.
Similarly, when screens are removed, deleting them asynchronously can trigger the same race condition.
This PR resolves the issue by synchronously deleting the surfaces first (delete surface;) before unlocking the session, conforming to the correct destruction order.
Fixes #540
Fixes #786
Fixes #733
Fixes #727
Fixes #608
Fixes #571
Fixes #406
Fixes #366
Fixes #368
Fixes #370
Fixes #361
Fixes #832