Skip to content

Conversation

@18202781743
Copy link
Contributor

@18202781743 18202781743 commented Jan 30, 2026

The crash occurred due to improper memory management of DockGroupModel
objects. Previously, m_groupModel was managed using QScopedPointer,
which could lead to premature deletion when the model was still in use.
The issue was fixed by changing to QObject parent-child relationship
management.

  1. Changed m_globalModel from raw pointer to QPointer for safer pointer
    tracking
  2. Changed m_groupModel from QScopedPointer to raw pointer with QObject
    parent-child relationship
  3. Modified DockGroupModel constructor to pass 'this' as parent
    parameter, enabling Qt's automatic object tree management
  4. Added nullptr initialization for m_groupModel in constructor
  5. Added null check in roleNames() method to prevent crashes when
    m_globalModel is null
  6. Removed unnecessary reset() call when switching to split mode

This ensures proper lifetime management where DockGroupModel instances
are automatically deleted when their parent DockItemModel is destroyed,
preventing use-after-free crashes.

Log: Fixed application crash when switching between window grouping
modes

Influence:

  1. Test switching between grouped and split window modes multiple times
  2. Verify no crashes occur during dock item model operations
  3. Test application stability when closing windows with grouped items
  4. Verify roleNames() method handles null m_globalModel gracefully
  5. Test memory management during model destruction scenarios

fix: 修复DockGroupModel析构问题导致的崩溃

崩溃是由于DockGroupModel对象的内存管理不当引起的。之前使用QScopedPointer
管理m_groupModel,可能导致模型仍在使用时被提前删除。通过改为使用QObject
父子关系管理解决了此问题。

  1. 将m_globalModel从原始指针改为QPointer,实现更安全的指针跟踪
  2. 将m_groupModel从QScopedPointer改为原始指针,使用QObject父子关系管理
  3. 修改DockGroupModel构造函数,传递'this'作为父参数,启用Qt的自动对象树
    管理
  4. 在构造函数中添加m_groupModel的nullptr初始化
  5. 在roleNames()方法中添加空检查,防止m_globalModel为空时崩溃
  6. 切换到分屏模式时移除不必要的reset()调用

这确保了正确的生命周期管理,当父对象DockItemModel被销毁时,
DockGroupModel实例会自动删除,防止了使用已释放内存导致的崩溃。

Log: 修复了在切换窗口分组模式时应用程序崩溃的问题

Influence:

  1. 测试多次切换分组和分屏窗口模式
  2. 验证在执行停靠栏项目模型操作时不会发生崩溃
  3. 测试关闭包含分组项目的窗口时的应用程序稳定性
  4. 验证roleNames()方法能正确处理空的m_globalModel
  5. 测试模型销毁场景下的内存管理

PMS: BUG-321495

Summary by Sourcery

Improve DockItemModel’s pointer management to prevent crashes when switching between grouped and split window modes.

Bug Fixes:

  • Prevent crashes caused by premature destruction of DockGroupModel while still in use.
  • Avoid potential null dereference in DockItemModel::roleNames() when the global model is missing.

Enhancements:

  • Manage the global task model via QPointer for safer lifetime tracking in DockItemModel.
  • Let DockGroupModel instances be owned by DockItemModel through QObject parent-child relationships instead of QScopedPointer.

The crash occurred due to improper memory management of DockGroupModel
objects. Previously, m_groupModel was managed using QScopedPointer,
which could lead to premature deletion when the model was still in use.
The issue was fixed by changing to QObject parent-child relationship
management.

1. Changed m_globalModel from raw pointer to QPointer for safer pointer
tracking
2. Changed m_groupModel from QScopedPointer to raw pointer with QObject
parent-child relationship
3. Modified DockGroupModel constructor to pass 'this' as parent
parameter, enabling Qt's automatic object tree management
4. Added nullptr initialization for m_groupModel in constructor
5. Added null check in roleNames() method to prevent crashes when
m_globalModel is null
6. Removed unnecessary reset() call when switching to split mode

This ensures proper lifetime management where DockGroupModel instances
are automatically deleted when their parent DockItemModel is destroyed,
preventing use-after-free crashes.

Log: Fixed application crash when switching between window grouping
modes

Influence:
1. Test switching between grouped and split window modes multiple times
2. Verify no crashes occur during dock item model operations
3. Test application stability when closing windows with grouped items
4. Verify roleNames() method handles null m_globalModel gracefully
5. Test memory management during model destruction scenarios

fix: 修复DockGroupModel析构问题导致的崩溃

崩溃是由于DockGroupModel对象的内存管理不当引起的。之前使用QScopedPointer
管理m_groupModel,可能导致模型仍在使用时被提前删除。通过改为使用QObject
父子关系管理解决了此问题。

1. 将m_globalModel从原始指针改为QPointer,实现更安全的指针跟踪
2. 将m_groupModel从QScopedPointer改为原始指针,使用QObject父子关系管理
3. 修改DockGroupModel构造函数,传递'this'作为父参数,启用Qt的自动对象树
管理
4. 在构造函数中添加m_groupModel的nullptr初始化
5. 在roleNames()方法中添加空检查,防止m_globalModel为空时崩溃
6. 切换到分屏模式时移除不必要的reset()调用

这确保了正确的生命周期管理,当父对象DockItemModel被销毁时,
DockGroupModel实例会自动删除,防止了使用已释放内存导致的崩溃。

Log: 修复了在切换窗口分组模式时应用程序崩溃的问题

Influence:
1. 测试多次切换分组和分屏窗口模式
2. 验证在执行停靠栏项目模型操作时不会发生崩溃
3. 测试关闭包含分组项目的窗口时的应用程序稳定性
4. 验证roleNames()方法能正确处理空的m_globalModel
5. 测试模型销毁场景下的内存管理

PMS: BUG-321495
@18202781743
Copy link
Contributor Author

企业微信截图_17695780329638

@sourcery-ai
Copy link

sourcery-ai bot commented Jan 30, 2026

Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Switches DockItemModel’s group model ownership from QScopedPointer to QObject parent-child semantics and makes the global model a QPointer, avoiding premature deletion and use-after-free crashes; also guards roleNames() against null globalModel and removes an unnecessary reset() when toggling split mode.

Sequence diagram for switching between split and grouped window modes

sequenceDiagram
    actor User
    participant DockItemModel
    participant GlobalModel as QAbstractItemModel
    participant GroupModel as DockGroupModel

    User->>DockItemModel: toggleWindowSplit(isWindowSplit)
    alt isWindowSplit == true
        DockItemModel->>DockItemModel: m_groupModel = nullptr
        DockItemModel->>DockItemModel: setSourceModel(m_globalModel)
    else isWindowSplit == false
        DockItemModel->>DockItemModel: m_groupModel = new DockGroupModel(m_globalModel, DesktopIdRole, this)
        DockItemModel->>DockItemModel: setSourceModel(m_groupModel)
    end
Loading

Sequence diagram for DockItemModel and DockGroupModel destruction via QObject parenting

sequenceDiagram
    participant QtEngine as QtObjectTree
    participant DockItemModel
    participant GroupModel as DockGroupModel

    QtEngine->>DockItemModel: destroy parent DockItemModel
    DockItemModel->>GroupModel: QObject parent-child destruction
    destroy GroupModel
    destroy DockItemModel
Loading

Class diagram for updated DockItemModel ownership and lifetime management

classDiagram

class QObject
class QAbstractItemModel
class QAbstractProxyModel
class AbstractTaskManagerInterface

class QPointer_QAbstractItemModel_ {
}

class DockGroupModel {
    +DockGroupModel(QAbstractItemModel* sourceModel, int groupRole, QObject* parent)
}

class DockItemModel {
    +DockItemModel(QAbstractItemModel* globalModel, QObject* parent)
    +QHash_int_QByteArray_ roleNames() const
    -QPointer_QAbstractItemModel_ m_globalModel
    -QAbstractItemModel* m_groupModel
    -bool m_split
    -bool m_isUpdating
}

DockItemModel --|> QAbstractProxyModel
DockItemModel --|> AbstractTaskManagerInterface
DockItemModel --> QPointer_QAbstractItemModel_ : uses
DockItemModel --> DockGroupModel : creates
DockGroupModel --|> QAbstractItemModel
DockItemModel --|> QObject
DockGroupModel --|> QObject
Loading

File-Level Changes

Change Details Files
Reworked DockItemModel’s model ownership and lifetime management to use QObject parenting and QPointer for safer handling of the global and group models.
  • Initialize m_groupModel to nullptr in the DockItemModel constructor member initializer list.
  • Replace QScopedPointer-based creation and teardown of DockGroupModel with a raw pointer constructed with DockItemModel as QObject parent and passed directly to setSourceModel.
  • Remove the explicit reset of the group model when switching back to split mode, relying on QObject’s parent-child destruction instead.
  • Change m_globalModel from a raw pointer to a QPointer to handle potential external deletion safely.
  • Change m_groupModel member from QScopedPointer to a raw QAbstractItemModel* with default nullptr initialization.
panels/dock/taskmanager/dockitemmodel.cpp
panels/dock/taskmanager/dockitemmodel.h
Hardened roleNames() to avoid crashes when the global model is missing.
  • Add a null check for m_globalModel at the start of roleNames() and return an empty hash if it has been cleared or was never set.
panels/dock/taskmanager/dockitemmodel.cpp

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey - I've found 1 issue, and left some high level feedback:

  • When switching repeatedly between split and grouped modes, a new DockGroupModel is allocated each time without deleting or reusing the previous instance, which can leak models until DockItemModel is destroyed; consider deleting the existing m_groupModel (or reusing it) before creating a new one.
  • Since m_groupModel is always constructed as a DockGroupModel, it may be clearer and safer to type m_groupModel as a DockGroupModel* rather than QAbstractItemModel* to make ownership and usage more explicit.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- When switching repeatedly between split and grouped modes, a new DockGroupModel is allocated each time without deleting or reusing the previous instance, which can leak models until DockItemModel is destroyed; consider deleting the existing m_groupModel (or reusing it) before creating a new one.
- Since m_groupModel is always constructed as a DockGroupModel, it may be clearer and safer to type m_groupModel as a DockGroupModel* rather than QAbstractItemModel* to make ownership and usage more explicit.

## Individual Comments

### Comment 1
<location> `panels/dock/taskmanager/dockitemmodel.cpp:29-33` </location>
<code_context>

         if (isWindowSplit) {
             setSourceModel(m_globalModel);
-            m_groupModel.reset(nullptr);
         } else {
-            m_groupModel.reset(new DockGroupModel(m_globalModel, TaskManager::DesktopIdRole));
-            setSourceModel(m_groupModel.get());
+            m_groupModel = new DockGroupModel(m_globalModel, TaskManager::DesktopIdRole, this);
+            setSourceModel(m_groupModel);
         }
     };
</code_context>

<issue_to_address>
**issue (bug_risk):** Avoid leaking DockGroupModel instances when toggling split mode off multiple times.

When `isWindowSplit` is false, a new `DockGroupModel` is created and parented to `this` each time, but the previous `m_groupModel` is never destroyed or reused. Over multiple toggles this will leak `DockGroupModel` instances and their signal/slot connections. Please either delete/reset the existing `m_groupModel` before assigning a new one, reuse a single instance, or switch back to a smart-pointer/RAII approach.
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@deepin-ci-robot
Copy link

deepin pr auto review

###,我将对这段代码进行详细的审查,并提供改进建议。

1. 代码变更概览

这段代码主要对 DockItemModel 类的成员变量管理和初始化逻辑进行了修改:

  1. m_globalModel 从普通指针改为 QPointer(弱引用指针)。
  2. m_groupModelQScopedPointer 改为普通指针,并初始化为 nullptr
  3. 在构造函数中移除了 m_groupModel.reset(nullptr) 的调用,并修改了 DockGroupModel 的创建方式,增加了 this 作为父对象。
  4. roleNames() 方法中增加了对 m_globalModel 的空指针检查。

2. 语法与逻辑审查

2.1 语法正确性

代码语法上是正确的,符合 C++ 和 Qt 的规范。

2.2 逻辑一致性

变更逻辑基本合理,特别是将 m_groupModel 的管理权交给 Qt 的对象树(通过设置父对象为 this),这可以确保在 DockItemModel 销毁时自动清理 m_groupModel

3. 代码质量改进建议

3.1 内存管理策略变更

问题:将 m_groupModelQScopedPointer 改为普通指针降低了内存管理的安全性。
建议

  • 如果目的是让 m_groupModel 的生命周期由 Qt 对象树管理,这是可以接受的,但需要确保 m_groupModel 始终有一个有效的父对象。
  • 考虑在析构函数中显式检查 m_groupModel 是否为 nullptr,虽然 Qt 会自动处理,但显式检查可以提高代码可读性。

3.2 指针类型混用

问题m_globalModel 使用 QPointer,而 m_groupModel 使用普通指针,这种不一致可能导致混淆。
建议

  • 如果 m_groupModel 的生命周期完全由 DockItemModel 控制,可以考虑继续使用 QScopedPointerQSharedPointer
  • 如果必须使用普通指针,建议添加注释说明其生命周期管理策略。

3.3 空指针检查

问题:虽然 roleNames() 增加了空指针检查,但其他使用 m_globalModel 的地方可能也需要类似检查。
建议

  • 审查所有使用 m_globalModel 的地方,确保在访问前进行空指针检查。
  • 考虑使用 Q_ASSERTQ_CHECK_PTR 在调试模式下捕获潜在的空指针问题。

4. 代码性能改进建议

4.1 指针访问开销

问题QPointer 相比普通指针有轻微的性能开销,因为每次解引用都需要检查对象是否已被删除。
建议

  • 如果 m_globalModel 的生命周期明确且不会在外部被意外删除,可以考虑使用普通指针。
  • 如果必须使用 QPointer,确保在性能敏感的代码路径中减少不必要的解引用操作。

5. 代码安全改进建议

5.1 悬空指针风险

问题:虽然 m_globalModel 使用了 QPointer,但 m_groupModel 作为普通指针,如果在外部被删除,可能导致悬空指针。
建议

  • 确保 m_groupModel 不会被外部删除,或者将其也改为 QPointer
  • DockItemModel 的析构函数中,如果 m_groupModel 仍然存在,可以安全地将其设置为 nullptr

5.2 线程安全

问题:如果 DockItemModel 可能在多线程环境中使用,指针的读写操作需要同步。
建议

  • 如果涉及多线程,考虑使用 QAtomicPointer 或添加适当的互斥锁保护指针访问。

6. 具体代码改进建议

6.1 头文件改进

// 建议在头文件中添加注释说明成员变量的生命周期管理
private:
    QPointer<QAbstractItemModel> m_globalModel; // 弱引用,可能在外部被删除
    QPointer<QAbstractItemModel> m_groupModel; // 改为 QPointer 以提高安全性
    bool m_split;
    bool m_isUpdating;

6.2 构造函数改进

DockItemModel::DockItemModel(QAbstractItemModel *globalModel, QObject *parent)
    : QAbstractProxyModel(parent)
    , AbstractTaskManagerInterface(this)
    , m_globalModel(globalModel)
    , m_groupModel(nullptr) // 显式初始化
    , m_split(!TaskManagerSettings::instance()->isWindowSplit())
    , m_isUpdating(false)
{
    // ... 其他代码 ...
}

6.3 roleNames() 方法改进

QHash<int, QByteArray> DockItemModel::roleNames() const
{
    if (!m_globalModel) {
        qWarning() << "m_globalModel is null in DockItemModel::roleNames()";
        return {};
    }
    return m_globalModel->roleNames();
}

7. 总结

这段代码的变更总体上是合理的,特别是将 m_groupModel 的管理权交给 Qt 对象树。但在指针类型的一致性和安全性方面还有改进空间。建议统一使用 QPointer 或明确注释说明不同指针的生命周期管理策略,并在所有访问指针的地方增加适当的空指针检查。

@deepin-ci-robot
Copy link

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743, BLumia

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@18202781743 18202781743 merged commit ebed3d8 into linuxdeepin:master Jan 30, 2026
10 of 11 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants