From b28c1a1580dbe4bf663565f3b150d5e2906cdc07 Mon Sep 17 00:00:00 2001 From: gongheng Date: Mon, 17 Aug 2026 18:42:13 +0800 Subject: [PATCH] fix: guard detail "More" button click against stale list access MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 1. 修复 PageDetail::slotBtnClicked 未校验按钮查找命中即按下标访问 m_ListTextBrowser 的越界崩溃; 2. clearWidget 在 deleteLater 旧 DetailButton 前先 disconnect 其 clicked 信号,阻断刷新重建期间旧按钮延迟销毁仍派发点击的时间窗; 3. 修复 showDeviceInfo 中 m_ListDetailSeperator[lstInfo.size()-1] 同类越界(if(!device) continue 致链表短于 lstInfo.size()),改用 last() 并判空; ===================================== 1. fix out-of-bounds access in PageDetail::slotBtnClicked where the button lookup result was not validated before indexing m_ListTextBrowser; 2. disconnect DetailButton::clicked before deleteLater in clearWidget to block stale clicks delivered during the deferred-deletion window after a refresh rebuild; 3. fix parallel out-of-bounds in showDeviceInfo where m_ListDetailSeperator[lstInfo.size()-1] could exceed list length when null devices were skipped, now uses last() with an empty check; Log: 修复扩展模式(多显示器)下点击显示设备“更多”按钮偶发闪退问题,根因为刷新重建页面时旧按钮延迟销毁期间其点击派发到已清空的按钮列表导致越界访问,通过校验查找命中与断开旧按钮信号根治 Bug: https://pms.uniontech.com/bug-view-308175.html --- deepin-devicemanager/src/Page/PageDetail.cpp | 24 ++++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/deepin-devicemanager/src/Page/PageDetail.cpp b/deepin-devicemanager/src/Page/PageDetail.cpp index eb214322..d728a9d2 100644 --- a/deepin-devicemanager/src/Page/PageDetail.cpp +++ b/deepin-devicemanager/src/Page/PageDetail.cpp @@ -211,9 +211,10 @@ void PageDetail::showDeviceInfo(const QList &lstInfo) connect(txtBrowser, &TextBrowser::exportInfo, this, &PageDetail::exportInfo); connect(txtBrowser, &TextBrowser::copyAllInfo, this, &PageDetail::slotCopyAllInfo); addWidgets(txtBrowser, device->enable() && device->available() && !device->getOtherTranslationAttribs().isEmpty()); - // 当添加到最后一个设备详细信息时,隐藏分隔符 - if (device == lstInfo.last()) - m_ListDetailSeperator[lstInfo.size() - 1]->setVisible(false); + // 当添加到最后一个设备详细信息时,隐藏分隔符。用last()而非lstInfo.size()-1, + // 因为if(!device) continue会跳过空设备,使链表实际长度可能小于lstInfo.size() + if (device == lstInfo.last() && !m_ListDetailSeperator.isEmpty()) + m_ListDetailSeperator.last()->setVisible(false); } // 刷新展示页面时,滚动条还原 mp_ScrollArea->verticalScrollBar()->setValue(0); @@ -360,8 +361,9 @@ void PageDetail::clearWidget() QList listDetailButton = m_ListDetailButton; m_ListDetailButton.clear(); - // 清空DetailButton + // 清空DetailButton,先断开clicked信号,避免延迟销毁期间旧按钮仍派发点击到slotBtnClicked foreach (auto widget, listDetailButton) { + disconnect(widget, &DetailButton::clicked, this, &PageDetail::slotBtnClicked); widget->deleteLater(); widget = nullptr; } @@ -395,16 +397,14 @@ void PageDetail::slotBtnClicked() DetailButton *button = qobject_cast(sender()); if (!button) return; - int index = 0; - foreach (DetailButton *b, m_ListDetailButton) { - if (button == b) - break; - index++; - } + + // 按钮可能因刷新重建已移出列表(clearWidget先清链表后deleteLater),此时忽略过期点击 + int index = m_ListDetailButton.indexOf(button); + if (index < 0 || index >= m_ListTextBrowser.size()) + return; // 改变按钮的状态,展开和收起的切换 - if (button) - button->updateText(); + button->updateText(); // 显示内容发生相应变化,也就是是否显示其它信息 TextBrowser *browser = m_ListTextBrowser[index];