fix: guard against layer-surface buffer-before-ack protocol error - #243
fix: guard against layer-surface buffer-before-ack protocol error#243AvengerAnubis wants to merge 5 commits into
Conversation
|
I'm gonna fix the CI errors, will push the fix commit soon |
|
Tested on my machine with Noctalia, seems to be working just fine. Before it (Noctalia in my case) was crashing every 5-10 minutes, now it's going with no crashes for 20 minutes at least |
0d1b8e0 to
e5115b7
Compare
|
Thanks for digging into this -- the diagnosis was on the right track, and it led me to a real bug one layer deeper than the patch. The root cause is on our side: layer_destroyed never removed the surface from the output's Fix and a regression test that reproduces the destroy-recreate sequence are on layer-destroy-unmap. Could you re-test with that and without your patch? If the crashes stop I'll close this as fixed differently -- you found the bug, and I'd like to credit you on it. |
|
Tested with your layer-destroy-unmap plus my local changes regarding dbus support for my particular use case (those shouldn't be affecting the test). Still crushes at random moments. driftwm logs that are probably related to the crush (output from dev version from my fork, the logger was added specificaly to catch this crush, which has been removed in last commit here): I think the PR #1991 (and the conversation there) may be related to this issue. |
Extend the pre-commit hook to check LockSurfaceData.last_acked in addition to LayerSurfaceData. Fixes the same commit-before-ack protocol error for ext_session_lock_surface_v1, which caused noctalia to crash when the lock screen attempted to commit a buffer before acknowledging the initial configure.
…d, wait for all surfaces before confirming lock
e5115b7 to
94eeaac
Compare
94eeaac to
eda8156
Compare
|
Thanks, so: smithay never unregisters its layer-shell pre-commit hook, and destroyed zeroes the role state, so later commits on that wl_surface validate against wiped state and post on a dead proxy. We already forced full anchors there, which covers the InvalidSize branches only -- the buffer-before-ack branch your patch neutralises was wide open. That's why your build is stable and my branch alone wasn't. I've gated it on "the role is dead" rather than last_acked.is_none(), so a premature buffer on a live role still errors, plus regression tests. Updated branch: layer-destroy-unmap. Could you re-test with it and without your patch? |
|
I tested it and sadly, noctalia still crashes with the same log message: |
|
I'm so sorry man, I forgot to push 😭 I also made driftwm log protocol-error disconnects itself; if it still dies, paste the line that reads "client ... disconnected: @ code=N — ". If it says |
|
Thats fine :D it happens to me too. |
|
I'm glad, pushed to main, thanks for diagnosing and sticking with me for testing! Closing this PR as fixed differently |
Problem
Noctalia (via quickshell) can commit a buffer to a
zwlr_layer_surface_v1before acknowledging the initial configure event. Smithay's layer-shell commit handler treats this asInvalidSurfaceStateprotocol error and kills the client (noctalia). This manifests as random crashes — especially when panels (clipboard history, etc.) are opened and closed rapidly.Root cause
Race in quickshell's layer-surface lifecycle — it attaches a buffer in the same dispatch cycle as the initial commit, before the configure event from the compositor has been processed and acknowledged.
Fix
A pre-commit hook (registered before smithay's validation hook in
new_surface) that readslast_ackedfrom the layer-surface role (LayerSurfaceData). Iflast_ackedis None (configure not yet acknowledged) and the pending state contains aNewBuffer, the buffer is removed (set toRemoved). Smithay's commit handler then sees no buffer, skips the protocol error, and the client safely acks the configure and retries the buffer on the next commit.Notes
LayerSurfaceData— regular xdg-toplevel windows are unaffected.last_ackedfrom the role data (LayerSurfaceAttributesviaLayerSurfaceData), not fromLayerSurfaceCachedState.pending()— the role'slast_ackedis updated immediately byack_configure, while the cached state is only synced on the next commit.