Skip to content

fix: drain global thread pool before app deletion to prevent crash on exit - #3509

Open
mhduiy wants to merge 1 commit into
linuxdeepin:masterfrom
mhduiy:agent/pms-bug-bot/0e03a4727738
Open

mhduiy wants to merge 1 commit into
linuxdeepin:masterfrom
mhduiy:agent/pms-bug-bot/0e03a4727738

Conversation

@mhduiy

@mhduiy mhduiy commented Sep 14, 2026 •

Copy link
Copy Markdown
Contributor

Root Cause Analysis

dde-control-center crashes with SIGSEGV during application exit under reboot stress testing. The root cause is a race condition in Qt 6.8's ~QCoreApplication() destructor: it sets QCoreApplication::self = nullptr before calling QThreadPool::globalInstance()->waitForDone(). Meanwhile, DccImageProvider uses the global thread pool for async image loading, and worker threads still running in QThread::exec() call notifyInternal2() which dereferences the now-null self pointer. The shutdown lambda in main.cpp deletes dccManager (cleaning the local thread pool) but does not drain the global thread pool before deleting app.

Fix

Added QThreadPool::globalInstance()->clear() and QThreadPool::globalInstance()->waitForDone() in the shutdown lambda, between delete dccManager and delete app. This ensures all global thread pool tasks are cleared and completed while QCoreApplication::self is still valid, preventing the destructor race condition. Also added #include <QThreadPool>.

Change Safety Assessment

Code Safety

  • Risk Level: Low
  • The shutdown lambda was recently introduced (2026-09-09) as part of the --list feature, not a previous bug fix — no risk of reverting a historical fix.
  • The new code is inside #ifdef DCC_ENABLE_MEMORY_MANAGEMENT, only affecting the exit path; no function signatures or public APIs are changed.

Business Impact Scope

The change only affects the application exit path (shutdown/reboot/logout scenarios). All normal control center operations (display, sound, network, account settings, etc.) are unaffected. The fix specifically prevents crashes during system reboot stress testing where dde-control-center exits while global thread pool tasks are still in-flight.

Verification Suggestion

Run reboot stress testing (5000+ cycles) to verify no SIGSEGV crashes occur during dde-control-center exit. Verify normal exit via window close and DBus quit still works without delay.


根因分析

dde-control-center 在重启压力测试中退出时发生 SIGSEGV 崩溃。根因是 Qt 6.8 的 ~QCoreApplication() 析构函数先将 QCoreApplication::self 置为 nullptr,再调用 QThreadPool::globalInstance()->waitForDone()。此时 DccImageProvider 通过全局线程池执行的异步图片加载任务仍在运行,工作线程在 QThread::exec() 中调用 notifyInternal2() 解引用已为空的 self 指针。main.cpp 的 shutdown lambda 在 delete dccManager(清理本地线程池)后直接 delete app,未在两者之间清空全局线程池。

修复方案

在 shutdown lambda 中 delete dccManager 与 delete app 之间新增 QThreadPool::globalInstance()->clear() 和 QThreadPool::globalInstance()->waitForDone(),确保在 QCoreApplication::self 仍有效时清空并等待全局线程池所有任务完成,消除析构竞态。同时添加 #include <QThreadPool>。

改动安全评估

代码安全评估

  • 风险等级: 低风险
  • shutdown lambda 为 2026-09-09 新引入的 --list 功能代码,非历史 bug 修复产物,不存在撤销历史修复的回归风险。
  • 新增代码位于 #ifdef DCC_ENABLE_MEMORY_MANAGEMENT 保护内,仅影响退出路径,不修改任何函数签名或公开接口。

业务影响范围

本次修改仅影响应用退出流程(关机/重启/注销场景)。控制中心的各项设置功能(显示、声音、网络、账户等)正常运行不受影响。修复专门针对系统重启压力测试中 dde-control-center 退出时全局线程池任务仍在运行导致的崩溃。

验证建议

执行重启压力测试(5000+ 次循环)验证 dde-control-center 退出时不再发生 SIGSEGV 崩溃。验证通过窗口关闭和 DBus quit 正常退出时无延迟。

Summary by Sourcery

Bug Fixes:

  • Prevent application-exit crashes by draining the global Qt thread pool before deleting the application instance.

… exit

In the shutdown lambda, after deleting dccManager and before deleting app,
explicitly clear and wait for the global thread pool to finish. This prevents
a race condition in Qt 6.8 where ~QCoreApplication() sets self = nullptr
before calling QThreadPool::globalInstance()->waitForDone(), causing worker
threads to dereference the null self pointer via notifyInternal2().

PMS: BUG-375601

fix: 退出前清空全局线程池防止崩溃

在 shutdown lambda 中,delete dccManager 之后、delete app 之前,显式调用
QThreadPool::globalInstance()->clear() 和 waitForDone() 清空并等待全局
线程池。防止 Qt 6.8 中 ~QCoreApplication() 先将 self 置 nullptr 再
waitForDone() 时,工作线程通过 notifyInternal2() 解引用空指针导致 SIGSEGV。

PMS: BUG-375601

@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.

Sorry @mhduiy, you've used your own review budget of 250,000 diff characters for the last 7 days.

You can request another review in 5 hours and 50 minutes by commenting @sourcery-ai review. Upgrade to get a review now.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: mhduiy

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

@sourcery-ai

sourcery-ai Bot commented Sep 14, 2026

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

Reviewer's Guide

Updates the managed-memory shutdown sequence to clear and synchronously drain Qt's global thread pool after deleting dccManager but before deleting the application, preventing in-flight image-loading workers from accessing a destroyed QCoreApplication during exit.

Sequence diagram for safe application shutdown

sequenceDiagram
    participant Shutdown as shutdown
    participant Manager as dccManager
    participant Pool as QThreadPool.globalInstance()
    participant App as QCoreApplication

    Shutdown->>Manager: delete dccManager
    Shutdown->>Pool: clear()
    Shutdown->>Pool: waitForDone()
    Pool-->>Shutdown: all global tasks completed
    Shutdown->>App: delete app
Loading

File-Level Changes

Change Details Files
Drain the Qt global thread pool before destroying the application object to eliminate the shutdown race.
  • Clear queued global thread-pool work.
  • Wait for active global thread-pool tasks to finish while QCoreApplication remains valid.
  • Add the QThreadPool header and keep the logic within the managed-memory shutdown path.
src/dde-control-center/main.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

@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

🤖 AI 代码审查报告

总体评分: 98 分 (通过阈值: 70分)

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 总体评分 98 分,大于 70 分通过阈值。本次提交修复了 Qt 6.8 中应用退出时的线程池竞态条件崩溃问题,代码变更简洁精准,无安全漏洞。

🔍 详细分析

1. 语法逻辑 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 语法正确,逻辑清晰。新增的 #include 头文件包含正确,QThreadPool::globalInstance()->clear() 和 waitForDone() 调用语法无误。代码放置位置正确:在 delete dccManager 之后、delete app 之前的 shutdown lambda 中,符合修复 Qt 6.8 竞态条件的逻辑要求。clear() 先清除未开始的待处理任务,waitForDone() 再等待正在运行的任务完成,操作顺序合理。


2. 代码质量 ✅

评价: 优秀 ✅ 通过

潜在问题:

  1. src/dde-control-center/main.cpp:237 - 新增的线程池清空代码缺少行内注释,建议添加简要注释说明 Qt 6.8 竞态条件修复原因

建议: 建议在 QThreadPool::globalInstance()->clear() 前添加行内注释,简要说明为何需要在 delete app 前清空线程池,例如:// Drain thread pool before app deletion to prevent Qt 6.8 crash (BUG-375601)


3. 代码性能 ✅

评价: 优秀 ✅ 通过

潜在问题:
✅ 未发现明显问题

建议: 性能良好,资源使用合理。waitForDone() 是阻塞调用,但在应用退出场景下是正确且必要的行为。clear() 清除未开始的待处理任务,避免不必要的等待。代码仅在 DCC_ENABLE_MEMORY_MANAGEMENT 宏定义时编译,不影响正常运行的性能。


4. 代码安全 🔒

评价: 优秀 ✅ 通过

🔐 发现 0 个安全漏洞

安全漏洞详情:
✅ 未发现安全漏洞

建议: 存在0个安全漏洞。本次变更不涉及用户输入处理、网络通信、文件操作等安全敏感场景。代码仅调用 Qt 框架的标准线程池管理接口,无注入风险、无敏感信息泄露、无权限绕过风险。修复实际上提升了程序的稳定性,防止了 SIGSEGV 崩溃。


💡 改进建议代码示例

// 在 shutdown lambda 中,delete dccManager 之后、delete app 之前
// 显式清空并等待全局线程池完成
// 防止 Qt 6.8 中 ~QCoreApplication() 先置 self=nullptr 再 waitForDone()
// 导致工作线程通过 notifyInternal2() 解引用空指针 (BUG-375601)
QThreadPool::globalInstance()->clear();
QThreadPool::globalInstance()->waitForDone();
delete app;

本报告由 AI 代码审查工具自动生成

@deepin-bot

deepin-bot Bot commented Sep 23, 2026

Copy link
Copy Markdown

TAG Bot

New tag: 6.1.109
DISTRIBUTION: unstable
Suggest: synchronizing this PR through rebase #3545

This branch has not been deployed

No deployments
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