Skip to content

Commit 681895c

Browse files
committed
fix: resolve null pointer crash when TextCalculator exits
1. Changed m_dataModel and m_calculator member variables from raw pointers to QPointer<QAbstractItemModel> and QPointer<TextCalculator> to automatically track object destruction 2. Added onDataModelDestroyed() slot to handle model destruction: clear m_dataModel pointer, emit dataModelChanged() signal, and reset calculated widths to prevent stale pointer access 3. Extracted width reset logic into resetCalculatedWidths() method to avoid code duplication and ensure consistent state cleanup 4. In scheduleCalculation(), call resetCalculatedWidths() when model is null or disabled to properly reset cached values 5. In setEnabled(false), replaced inline width reset with resetCalculatedWidths() call for consistency 6. In destructor, always call disconnectDataModelSignals() without null check, as QPointer ensures safe disconnection even if model is destroyed 7. In TextCalculatorAttached::setCalculator(), added guard for duplicate calculator assignment and proper disconnect of previous calculator signals to prevent double connections 8. Always call updateElidedText() even when calculator is null to ensure text is properly cleared 9. Added QPointer include in header for QPointer usage Log: Fixed null pointer crash during TextCalculator exit in dock task panel Influence: 1. Test dock task panel close and exit operations to verify no crashes occur 2. Verify task item text display updates correctly when tasks change 3. Test with rapid task creation/deletion scenarios to check memory safety 4. Verify elided text updates properly when calculator is reassigned 5. Test disabled state transitions to confirm width values are reset correctly fix: 修复 TextCalculator 退出时的野指针崩溃问题 1. 将 m_dataModel 和 m_calculator 成员变量从原始指针改为 QPointer<QAbstractItemModel> 和 QPointer<TextCalculator>,自动追踪对象 销毁 2. 新增 onDataModelDestroyed() 槽函数处理模型销毁:清除 m_dataModel 指 针、发射 dataModelChanged() 信号并重置计算宽度,防止野指针访问 3. 将宽度重置逻辑提取为 resetCalculatedWidths() 方法,避免代码重复并确保 状态一致清理 4. 在 scheduleCalculation() 中,当模型为空或禁用时调用 resetCalculatedWidths() 正确重置缓存值 5. 在 setEnabled(false) 中,将内联宽度重置替换为 resetCalculatedWidths() 调用,保持一致性 6. 在析构函数中,始终调用 disconnectDataModelSignals() 而不进行空检查, 因为 QPointer 确保即使模型已销毁也能安全断开连接 7. 在 TextCalculatorAttached::setCalculator() 中,添加重复计算器赋值防 护,并正确断开前一个计算器的信号连接,防止重复连接 8. 即使计算器为空也始终调用 updateElidedText(),确保正确清理文本 9. 在头文件中添加 QPointer 包含以支持 QPointer 使用 Log: 修复 Dock 任务面板 TextCalculator 退出时的野指针崩溃问题 Influence: 1. 测试 dock 任务面板的关闭和退出操作,验证无崩溃发生 2. 验证任务项文本显示在任务变更时正确更新 3. 测试快速创建/删除任务场景,检查内存安全性 4. 验证当计算器重新赋值时省略文本正确更新 5. 测试禁用状态切换,确认宽度值正确重置
1 parent 96c0307 commit 681895c

2 files changed

Lines changed: 54 additions & 20 deletions

File tree

panels/dock/taskmanager/textcalculator.cpp

Lines changed: 48 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2025-2026 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2025 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

@@ -30,9 +30,7 @@ TextCalculator::TextCalculator(QObject *parent)
3030

3131
TextCalculator::~TextCalculator()
3232
{
33-
if (m_dataModel) {
34-
disconnectDataModelSignals();
35-
}
33+
disconnectDataModelSignals();
3634
}
3735

3836
void TextCalculator::setFont(const QFont &font)
@@ -113,10 +111,7 @@ void TextCalculator::setEnabled(bool enabled)
113111
if (m_enabled) {
114112
scheduleCalculation();
115113
} else {
116-
m_optimalSingleTextWidth = 0.0;
117-
m_totalWidth = 0;
118-
emit optimalSingleTextWidthChanged();
119-
emit totalWidthChanged();
114+
resetCalculatedWidths();
120115
}
121116
emit enabledChanged();
122117
}
@@ -137,11 +132,12 @@ void TextCalculator::connectDataModelSignals()
137132
this,
138133
[this](const QModelIndex &topLeft, const QModelIndex &bottomRight, const QList<int> &roles) {
139134
const auto titleRole = m_dataModel->roleNames().key("title");
140-
if (roles.contains(titleRole) || roles.isEmpty()) {
141-
scheduleCalculation();
142-
}
143-
});
135+
if (roles.contains(titleRole) || roles.isEmpty()) {
136+
scheduleCalculation();
137+
}
138+
});
144139
connect(m_dataModel, &QAbstractItemModel::modelReset, this, &TextCalculator::onDataModelChanged);
140+
connect(m_dataModel, &QObject::destroyed, this, &TextCalculator::onDataModelDestroyed);
145141
}
146142
}
147143

@@ -157,17 +153,41 @@ void TextCalculator::onDataModelChanged()
157153
scheduleCalculation();
158154
}
159155

156+
void TextCalculator::onDataModelDestroyed()
157+
{
158+
m_dataModel = nullptr;
159+
emit dataModelChanged();
160+
resetCalculatedWidths();
161+
}
162+
160163
void TextCalculator::scheduleCalculation()
161164
{
162165
if (!complete)
163166
return;
164167

165168
if (!m_enabled || !m_dataModel) {
169+
resetCalculatedWidths();
166170
return;
167171
}
168172
calculateOptimalTextWidth();
169173
}
170174

175+
void TextCalculator::resetCalculatedWidths()
176+
{
177+
const bool optimalWidthWasSet = !qFuzzyIsNull(m_optimalSingleTextWidth);
178+
const bool totalWidthWasSet = !qFuzzyIsNull(m_totalWidth);
179+
180+
m_optimalSingleTextWidth = 0.0;
181+
m_totalWidth = 0.0;
182+
183+
if (optimalWidthWasSet) {
184+
emit optimalSingleTextWidthChanged();
185+
}
186+
if (totalWidthWasSet) {
187+
emit totalWidthChanged();
188+
}
189+
}
190+
171191
qreal TextCalculator::calculateBaselineWidth(int charCount) const
172192
{
173193
if (m_baselineWidthCache.contains(charCount)) {
@@ -372,11 +392,22 @@ QString TextCalculatorAttached::elidedText() const
372392

373393
void TextCalculatorAttached::setCalculator(TextCalculator *calculator)
374394
{
375-
if (calculator) {
376-
m_calculator = calculator;
377-
connect(calculator, &TextCalculator::optimalSingleTextWidthChanged, this, &TextCalculatorAttached::updateElidedText);
378-
updateElidedText();
395+
if (m_calculator == calculator) {
396+
return;
397+
}
398+
399+
if (m_calculator) {
400+
disconnect(m_calculator, nullptr, this, nullptr);
401+
}
402+
403+
m_calculator = calculator;
404+
emit calculatorChanged();
405+
406+
if (m_calculator) {
407+
connect(m_calculator, &TextCalculator::optimalSingleTextWidthChanged, this, &TextCalculatorAttached::updateElidedText);
379408
}
409+
410+
updateElidedText();
380411
}
381412

382413
TextCalculator *TextCalculatorAttached::calculator()
@@ -422,7 +453,7 @@ void TextCalculatorAttached::updateElidedText()
422453
if (visibleText.isEmpty()) {
423454
visibleText = {};
424455
}
425-
456+
426457
if (visibleText != m_text) {
427458
m_ellipsisWidth = fontMetrics.horizontalAdvance(QString::fromUtf8(""));
428459
emit ellipsisWidthChanged();

panels/dock/taskmanager/textcalculator.h

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
1-
// SPDX-FileCopyrightText: 2025-2026 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2025 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: GPL-3.0-or-later
44

55
#pragma once
66

77
#include <QAbstractItemModel>
88
#include <QFont>
9+
#include <QPointer>
910
#include <QtQml/QtQml>
1011

1112
namespace dock
@@ -55,7 +56,7 @@ private Q_SLOTS:
5556
QString m_text;
5657
QString m_elidedText;
5758
qreal m_ellipsisWidth = 0.0;
58-
TextCalculator *m_calculator;
59+
QPointer<TextCalculator> m_calculator;
5960
bool m_initialized = false;
6061
};
6162

@@ -159,12 +160,14 @@ class TextCalculator : public QObject, public QQmlParserStatus
159160

160161
private slots:
161162
void onDataModelChanged();
163+
void onDataModelDestroyed();
162164
void calculateOptimalTextWidth();
163165

164166
private:
165167
void connectDataModelSignals();
166168
void disconnectDataModelSignals();
167169
void scheduleCalculation();
170+
void resetCalculatedWidths();
168171

169172
qreal calculateBaselineWidth(int charCount) const;
170173
qreal calculateElidedTextWidth(const QString &text, qreal maxWidth) const;
@@ -178,7 +181,7 @@ private slots:
178181
qreal m_cellSize;
179182
int m_spacing;
180183
int m_itemPadding;
181-
QAbstractItemModel *m_dataModel;
184+
QPointer<QAbstractItemModel> m_dataModel;
182185
qreal m_remainingSpace;
183186
bool m_enabled;
184187

0 commit comments

Comments
 (0)