From 4a8f6c22ce7c52929aa2b57b3c6fcfe39e0e9c12 Mon Sep 17 00:00:00 2001 From: deepin-wm Date: Thu, 18 Jun 2026 20:14:35 +0800 Subject: [PATCH] fix: prevent crash from dangling ptr and null seatClient MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. Add SurfaceWrapper::aboutToBeInvalidated connection in registerSurfaceToForeignToplevel to call removeSurface when a registered SurfaceWrapper is about to be invalidated 2. Fix dangling pointer in ForeignToplevelManagerInterfaceV1::m_surfaces caused by missing removeSurface call during surface destruction 3. Add null pointer checks for seatClient in 5 locations within InputManagerInterfaceV1 to prevent crash when client disconnects Log: Fixed crash when hot-plugging screens during control center operation Influence: 1. Test hot-plugging external screens while control center is opening 2. Verify no crash when disconnecting clients during capability broadcast 3. Test system stability during rapid screen plug/unplug cycles 4. Verify ForeignToplevel surfaces are properly cleaned up on removal 5. Test input device hot-plug with multiple Wayland clients connected fix: 修复悬空指针和seatClient空指针导致的崩溃 1. 在registerSurfaceToForeignToplevel中添加SurfaceWrapper::aboutToBeInvalidated连接 在SurfaceWrapper即将失效时调用removeSurface 2. 修复ForeignToplevelManagerInterfaceV1::m_surfaces中因缺失 removeSurface调用导致的悬空指针问题 3. 在InputManagerInterfaceV1的5处位置添加seatClient空指针检查 防止客户端断开时崩溃 Log: 修复双屏热插拔时控制中心崩溃的问题 Influence: 1. 测试打开控制中心时热插拔扩展屏是否正常 2. 验证客户端断开连接时能力广播不会崩溃 3. 测试快速拔插屏幕时系统稳定性 4. 验证ForeignToplevel表面移除时正确清理 5. 测试多个Wayland客户端连接时输入设备热插拔 Fixes: #183 --- src/core/shellhandler.cpp | 4 ++++ .../input-manager/inputmanagerinterfacev1.cpp | 15 +++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/src/core/shellhandler.cpp b/src/core/shellhandler.cpp index 72521e125..2d19c5e14 100644 --- a/src/core/shellhandler.cpp +++ b/src/core/shellhandler.cpp @@ -779,6 +779,10 @@ void ShellHandler::registerSurfaceToForeignToplevel(SurfaceWrapper *wrapper) m_treelandForeignToplevel->addSurface(wrapper); } }); + + connect(wrapper, &SurfaceWrapper::aboutToBeInvalidated, this, [this, wrapper] { + m_treelandForeignToplevel->removeSurface(wrapper); + }); } void ShellHandler::setupDockPreview() diff --git a/src/modules/input-manager/inputmanagerinterfacev1.cpp b/src/modules/input-manager/inputmanagerinterfacev1.cpp index 3a227dfae..5b7297246 100644 --- a/src/modules/input-manager/inputmanagerinterfacev1.cpp +++ b/src/modules/input-manager/inputmanagerinterfacev1.cpp @@ -54,6 +54,9 @@ void TreelandInputManagerInterfaceV1Private::bind_resource(Resource *resource) { TreelandInputManagerInterfaceV1::DeviceTypes types = q->inputDeviceListTypes(); struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + return; + struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { send_capability_available(resource->handle, types.toInt(), clientResource); @@ -173,6 +176,9 @@ void TreelandInputManagerInterfaceV1::sendCapabilityAvailable(TreelandInputManag for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; + struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_available(resource->handle, types.toInt(), clientResource); @@ -185,6 +191,9 @@ void TreelandInputManagerInterfaceV1::sendCapabilityUnavailable(TreelandInputMan for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; + struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_unavailable(resource->handle, types.toInt(), clientResource); @@ -267,6 +276,9 @@ void TreelandInputManagerInterfaceV1::onInputAdded(WInputDevice *input) for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; + struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_available(resource->handle, type.toInt(), clientResource); @@ -292,6 +304,9 @@ void TreelandInputManagerInterfaceV1::onInputRemoved(WInputDevice *input) for (const auto &resource : d->resourceMap()) { struct wlr_seat_client *seatClient = Helper::instance()->seat()->handle()->client_for_wl_client(resource->client()); + if (!seatClient) + continue; + struct wl_resource *clientResource; wl_resource_for_each(clientResource, &seatClient->resources) { d->send_capability_unavailable(resource->handle, type.toInt(), clientResource);