From af4ed0ae3c21ae91f0cb1416afb397468f1e05c9 Mon Sep 17 00:00:00 2001 From: Simao Gomes Viana Date: Wed, 21 Jan 2026 11:59:33 +0100 Subject: [PATCH] hyprland/ipc: use deleteLater() for workspace and toplevel deletion Fix use-after-free crash when rapidly switching workspaces. The crash occurs because QML bindings may still reference workspace/toplevel objects during the same event loop iteration after immediate deletion. Crash stack trace: #0 QV4::QObjectWrapper::wrap (libQt6Qml.so.6) #1 QV4::loadProperty (libQt6Qml.so.6) #2 QV4::QQmlTypeWrapper::lookupSingletonProperty (libQt6Qml.so.6) Using deleteLater() defers deletion to the next event loop iteration, ensuring all QML bindings have completed their updates first. --- src/wayland/hyprland/ipc/connection.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/wayland/hyprland/ipc/connection.cpp b/src/wayland/hyprland/ipc/connection.cpp index ad091a6f..809faed9 100644 --- a/src/wayland/hyprland/ipc/connection.cpp +++ b/src/wayland/hyprland/ipc/connection.cpp @@ -359,8 +359,8 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { qCDebug(logHyprlandIpc) << "Workspace removed with id" << id << "name" << name; this->mWorkspaces.removeAt(index); - // workspaces have not been observed to be referenced after deletion - delete workspace; + // Use deleteLater to ensure QML bindings don't access dangling pointers + workspace->deleteLater(); for (auto* monitor: this->mMonitors.valueList()) { if (monitor->bindableActiveWorkspace().value() == nullptr) { @@ -494,7 +494,8 @@ void HyprlandIpc::onEvent(HyprlandIpcEvent* event) { workspace->toplevels()->removeObject(toplevel); } - delete toplevel; + // Use deleteLater to ensure QML bindings don't access dangling pointers + toplevel->deleteLater(); } else if (event->name == "movewindowv2") { auto args = event->parseView(3); auto ok = false; @@ -662,7 +663,8 @@ void HyprlandIpc::refreshWorkspaces(bool canCreate) { for (auto* workspace: removedWorkspaces) { this->mWorkspaces.removeObject(workspace); - delete workspace; + // Use deleteLater to ensure QML bindings don't access dangling pointers + workspace->deleteLater(); } } });