Skip to content

fix: fix autoExitTimer crash in DBusControlCenterGrandSearchService#3309

Closed
fly602 wants to merge 0 commit into
linuxdeepin:masterfrom
fly602:master
Closed

fix: fix autoExitTimer crash in DBusControlCenterGrandSearchService#3309
fly602 wants to merge 0 commit into
linuxdeepin:masterfrom
fly602:master

Conversation

@fly602

@fly602 fly602 commented Jun 22, 2026

Copy link
Copy Markdown
Contributor
  1. Added QPointer protection for both adaptor and manager in autoExitTimer lambda capture to prevent Use-After-Free crash
  2. Modified destructor to disconnect all signal connections and stop timer to prevent callbacks from firing after object destruction
  3. Used QPointer to protect 'this' pointer in lambda capture
  4. Used QPointer to protect parent manager pointer

Log: Fixed control center crash caused by autoExitTimer Use-After-Free

Influence:

  1. Test control center auto-exit behavior via DBus calls
  2. Verify timer behavior when adaptor is destroyed before timer fires
  3. Test GrandSearch functionality with proper timer cleanup
  4. Verify control center stability during rapid show/hide cycles

fix: 修复DBusControlCenterGrandSearchService中autoExitTimer崩溃问题

  1. 在autoExitTimer的lambda捕获中添加QPointer保护adaptor和manager, 防止Use-After-Free崩溃
  2. 修改析构函数,断开所有信号连接并停止定时器,防止回调在对象销毁后 仍然触发
  3. 使用QPointer保护lambda中的this指针
  4. 使用QPointer保护父对象manager指针

Log: 修复控制中心因autoExitTimer Use-After-Free导致的崩溃

Influence:

  1. 通过DBus调用测试控制中心自动退出行为
  2. 验证adaptor在定时器触发前被销毁时的定时器行为
  3. 测试GrandSearch功能的定时器清理
  4. 验证控制中心在快速显示/隐藏周期中的稳定性

PMS: BUG-362939

Summary by Sourcery

Prevent DBus control center grand search auto-exit timer from causing use-after-free crashes by guarding lifetime and cleaning up on destruction.

Bug Fixes:

  • Guard the auto-exit timer callback with QPointer-checked adaptor and manager instances to avoid use-after-free when objects are destroyed before timeout.
  • Stop the auto-exit timer and disconnect its signals in the grand search service destructor to prevent callbacks after object destruction.

@sourcery-ai

sourcery-ai Bot commented Jun 22, 2026

Copy link
Copy Markdown
Reviewer's guide (collapsed on small PRs)

Reviewer's Guide

Adds QPointer-based lifetime protection around the auto-exit timer callback in DBusControlCenterGrandSearchService and ensures the timer is safely disconnected and stopped in the destructor to prevent use-after-free crashes.

Sequence diagram for autoExitTimer with QPointer lifetime protection

sequenceDiagram
    participant Service as DBusControlCenterGrandSearchService
    participant Manager as DccManager
    participant AutoExitTimer as QTimer
    participant App as QCoreApplication

    Service->>AutoExitTimer: setInterval(10000)
    Service->>AutoExitTimer: setSingleShot(true)
    Service->>AutoExitTimer: connect(timeout, lambda[self, manager])
    Service->>AutoExitTimer: start()

    AutoExitTimer-->>Service: timeout()
    alt [self && manager]
        AutoExitTimer->>Manager: mainWindow()
        Manager-->>AutoExitTimer: mainWindow
        AutoExitTimer->>Manager: mainWindow()->isVisible()
        alt [!isVisible]
            AutoExitTimer->>App: quit()
        end
    else [!self || !manager]
        AutoExitTimer-->>AutoExitTimer: return
    end

    destroy Service
    Service->>AutoExitTimer: disconnect(m_autoExitTimer, nullptr, this, nullptr)
    Service->>AutoExitTimer: stop()
Loading

File-Level Changes

Change Details Files
Hardened auto-exit timer callback against use-after-free by guarding captured objects with QPointer and using the manager instead of parent()->mainWindow().
  • Included QPointer header to enable guarded pointers.
  • Introduced QPointer self and QPointer manager before connecting the auto-exit timer.
  • Replaced lambda capture of raw this/parent with [self, manager] and added null checks for both before accessing mainWindow().
  • Switched from calling parent()->mainWindow() to manager->mainWindow() inside the timer callback.
src/dde-control-center/controlcenterdbusadaptor.cpp
Made destruction of DBusControlCenterGrandSearchService explicitly stop and disconnect the auto-exit timer to avoid callbacks after destruction.
  • Replaced empty destructor with an implementation that disconnects m_autoExitTimer signal connections to this.
  • Explicitly stops m_autoExitTimer in the destructor to ensure no pending timeout will fire after object destruction.
src/dde-control-center/controlcenterdbusadaptor.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

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown

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:

  • The local QPointer<DBusControlCenterGrandSearchService> self is captured into the lambda but never used, so it can be removed from both the local variables and capture list to simplify the code.
  • In the destructor, consider guarding the disconnect/stop calls with a null check on m_autoExitTimer (or a clear invariant comment) to make it explicit that the timer is always constructed and valid at this point.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The local `QPointer<DBusControlCenterGrandSearchService> self` is captured into the lambda but never used, so it can be removed from both the local variables and capture list to simplify the code.
- In the destructor, consider guarding the `disconnect`/`stop` calls with a null check on `m_autoExitTimer` (or a clear invariant comment) to make it explicit that the timer is always constructed and valid at this point.

## Individual Comments

### Comment 1
<location path="src/dde-control-center/controlcenterdbusadaptor.cpp" line_range="149-157" />
<code_context>
-        if (!this->parent()->mainWindow()->isVisible())
+
+    // 使用 QPointer 同时保护 adaptor 和 manager,防止 Use-After-Free
+    QPointer<DBusControlCenterGrandSearchService> self = this;
+    QPointer<DccManager> manager = parent;
+
+    connect(m_autoExitTimer, &QTimer::timeout, this, [self, manager]() {
+        // 检查 adaptor 和 manager 都还存在
+        if (self && manager && !manager->mainWindow()->isVisible())
</code_context>
<issue_to_address>
**suggestion:** Consider simplifying lifetime handling by avoiding redundant `QPointer` + context usage.

Because `connect` uses `this` as the context, Qt will already disconnect the lambda when `DBusControlCenterGrandSearchService` is destroyed, so `QPointer<...> self` guards the same lifetime twice. That redundancy makes the lifetime model harder to follow without adding real safety.

You could either:
- Keep the context object (`this`) and drop `self` from the capture, only guarding `manager` with `QPointer`, or
- Use `nullptr` as the context and rely solely on `QPointer` for both `self`/`manager`, avoiding raw `this`.

Both options keep use‑after‑free protection while simplifying lifetime management.

```suggestion
    // 使用 QPointer 保护 manager,避免管理器销毁后访问悬空指针
    QPointer<DccManager> manager = parent;

    connect(m_autoExitTimer, &QTimer::timeout, this, [manager]() {
        // 检查 manager 仍然存在且主窗口不可见
        if (manager && !manager->mainWindow()->isVisible())
            QCoreApplication::quit();
    });
```
</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.

Comment on lines 149 to 157
// 使用 QPointer 同时保护 adaptor 和 manager,防止 Use-After-Free
QPointer<DBusControlCenterGrandSearchService> self = this;
QPointer<DccManager> manager = parent;

connect(m_autoExitTimer, &QTimer::timeout, this, [self, manager]() {
// 检查 adaptor 和 manager 都还存在
if (self && manager && !manager->mainWindow()->isVisible())
QCoreApplication::quit();
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

suggestion: Consider simplifying lifetime handling by avoiding redundant QPointer + context usage.

Because connect uses this as the context, Qt will already disconnect the lambda when DBusControlCenterGrandSearchService is destroyed, so QPointer<...> self guards the same lifetime twice. That redundancy makes the lifetime model harder to follow without adding real safety.

You could either:

  • Keep the context object (this) and drop self from the capture, only guarding manager with QPointer, or
  • Use nullptr as the context and rely solely on QPointer for both self/manager, avoiding raw this.

Both options keep use‑after‑free protection while simplifying lifetime management.

Suggested change
// 使用 QPointer 同时保护 adaptor 和 manager,防止 Use-After-Free
QPointer<DBusControlCenterGrandSearchService> self = this;
QPointer<DccManager> manager = parent;
connect(m_autoExitTimer, &QTimer::timeout, this, [self, manager]() {
// 检查 adaptor 和 manager 都还存在
if (self && manager && !manager->mainWindow()->isVisible())
QCoreApplication::quit();
});
// 使用 QPointer 保护 manager,避免管理器销毁后访问悬空指针
QPointer<DccManager> manager = parent;
connect(m_autoExitTimer, &QTimer::timeout, this, [manager]() {
// 检查 manager 仍然存在且主窗口不可见
if (manager && !manager->mainWindow()->isVisible())
QCoreApplication::quit();
});

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

★ 总体评分:100分

■ 【总体评价】

代码完美修复了定时器回调中的悬空指针引用问题,防御性编程到位
逻辑严密且无任何安全漏洞,符合满分标准

■ 【详细分析】

  • 1.语法逻辑完全正确✓

DBusControlCenterGrandSearchService 构造函数中,使用 QPointer 捕获 thisparent 指针,并在 lambda 中进行判空,彻底避免了对象析构后的非法内存访问。析构函数中调用 disconnect(m_autoExitTimer, nullptr, this, nullptr) 准确切断了信号槽连接,语法和生命周期管理完全正确。
建议:保持当前的防御性编程风格。

  • 2.代码质量良好✓

修复代码针对性强,注释清晰说明了使用 QPointerdisconnect 的目的。通过引入智能指针包装代替裸指针捕获,代码可读性与健壮性得到双重提升。
建议:无需额外修改。

  • 3.代码性能无性能问题✓

QPointer 仅是对原生指针的轻量级包装,内部通过 QObject 的销毁信号进行置空操作,在定时器超时这种低频回调场景下几乎不产生性能损耗。
建议:维持现状即可。

  • 4.代码安全存在0个安全漏洞✓

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个
本次修改成功消除了原有的 Use-After-Free 严重内存安全问题,未引入任何新的安全漏洞。原漏洞在 DBusControlCenterGrandSearchService 构造函数的 lambda 回调中捕获裸指针 this,当对象提前析构时触发崩溃,现已通过 QPointer 完全阻断该攻击面。

  • 建议:继续保持对异步回调中指针生命周期的严格管控。

■ 【改进建议代码示例】

// 当前代码已为最佳实践,无需进一步修改,此处展示其核心逻辑以供参考
#include <QPointer>

DBusControlCenterGrandSearchService::DBusControlCenterGrandSearchService(DccManager *parent)
    : QDBusAbstractAdaptor(parent)
    , m_autoExitTimer(new QTimer(this))
{
    m_autoExitTimer->setInterval(10000);
    m_autoExitTimer->setSingleShot(true);

    QPointer<DBusControlCenterGrandSearchService> self = this;
    QPointer<DccManager> manager = parent;

    connect(m_autoExitTimer, &QTimer::timeout, this, [self, manager]() {
        if (self && manager && !manager->mainWindow()->isVisible())
            QCoreApplication::quit();
    });
    m_autoExitTimer->start();
}

DBusControlCenterGrandSearchService::~DBusControlCenterGrandSearchService()
{
    disconnect(m_autoExitTimer, nullptr, this, nullptr);
    m_autoExitTimer->stop();
}

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: fly602

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

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.

2 participants