Skip to content

fix: prevent SVG cache tasks from outliving application - #327

Open
18202781743 wants to merge 1 commit into
linuxdeepin:masterfrom
18202781743:fix-dsvgicon-cache-shutdown
Open

18202781743 wants to merge 1 commit into
linuxdeepin:masterfrom
18202781743:fix-dsvgicon-cache-shutdown

Conversation

@18202781743

@18202781743 18202781743 commented Sep 11, 2026

Copy link
Copy Markdown
Contributor

SVG icon cache writes run asynchronously through QImage::save(). During
application shutdown these tasks can outlive the Qt image plugin loader and
crash in QFactoryLoader.

Use an application-owned thread pool for cache writes. On aboutToQuit, stop
accepting cache jobs, discard queued jobs, and wait for the active jobs to
finish. Normal icon rendering remains asynchronous.

Validation:

  • cmake --build build --target dsvgicon -j6
  • ut_QSvgIconEngine: 7 assertions passed
  • git diff --check

Summary by Sourcery

Ensure SVG cache writes finish safely before the application exits.

Bug Fixes:

  • Prevent asynchronous SVG icon cache writes from accessing Qt image infrastructure after application shutdown.

Enhancements:

  • Manage cache-write tasks with an application-owned thread pool that stops accepting work, clears queued jobs, and waits for active jobs during shutdown.

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: 18202781743

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 11, 2026

Copy link
Copy Markdown

Reviewer's Guide

The PR prevents SVG cache-writing tasks from surviving application shutdown by using an application-owned QThreadPool that drains safely during aboutToQuit, while preserving asynchronous rendering. It also standardizes Chameleon’s Wayland detection through DGuiApplicationHelper.

Sequence diagram for safe SVG cache shutdown

sequenceDiagram
    participant App as QCoreApplication
    participant Engine as QSvgIconEngine
    participant Pool as IconCachePool
    participant Worker as CacheWorker
    participant Plugin as QtImagePluginLoader

    Engine->>Pool: instance()
    Pool-->>Engine: application-owned pool
    Engine->>Pool: QtConcurrent.run(pool, cache write)
    Pool->>Worker: execute QSaveFile and image.save()
    Worker->>Plugin: image.save()
    App-->>Pool: aboutToQuit
    Pool->>Pool: clear()
    Pool->>Pool: waitForDone()
    Worker-->>Pool: active cache job finishes
    Pool-->>App: shutdown continues safely
Loading

File-Level Changes

Change Details Files
Own SVG cache writes in an application-lifetime thread pool and coordinate shutdown with queued and active work.
  • Create a lazily initialized pool parented to QCoreApplication and only expose it from the application thread.
  • Reject new cache jobs after aboutToQuit, clear queued jobs, and wait for running writes to finish.
  • Route asynchronous PNG cache writes through the owned pool while leaving icon rendering asynchronous.
iconengineplugins/svgiconengine/qsvgiconengine.cpp
Use the centralized GUI helper to detect Wayland instead of platform-specific configuration and property checks.
  • Replace direct platform-name and private property checks with IsWaylandPlatform attribute testing.
  • Update the style dependency to include the GUI application helper API.
styleplugins/chameleon/chameleonstyle.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

@18202781743
18202781743 force-pushed the fix-dsvgicon-cache-shutdown branch from caae49a to c3e43c9 Compare September 11, 2026 09:17

@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 reviewed your changes and they look great!


Sourcery is free for open source - if you like our reviews please consider sharing them ✨

1. Replace the global thread pool with a dedicated IconCachePool for SVG
icon cache writes
2. Tie the pool's lifetime to QCoreApplication via QPointer so it is
invalidated on shutdown
3. Connect to QCoreApplication::aboutToQuit to clear pending tasks and
wait for completion
4. Guard pool creation to the application's main thread and return
nullptr once stopped
5. Skip cache writes entirely when no valid pool is available to avoid
dangling tasks

Influence:
1. Verify SVG icons still render correctly and cache files are written
under normal use
2. Test application shutdown while many icon cache tasks are queued,
ensure no crashes or warnings about destroyed threads
3. Confirm no tasks run on a destroyed QCoreApplication and no leaks
are reported
4. Test cache file creation, commit, and timestamp updates remain
functional
5. Verify behavior when pixmap rendering happens from non-main threads
(pool should be skipped)
6. Check that icons without cache file paths still render without
regressions

fix: 防止 SVG 缓存任务超出应用生命周期

1. 使用专用的 IconCachePool 替代全局线程池来处理 SVG 图标缓存写入
2. 通过 QPointer 将线程池生命周期绑定到 QCoreApplication,在退出时自动
失效
3. 连接 QCoreApplication::aboutToQuit,清除待处理任务并等待完成
4. 限制线程池仅在应用主线程创建,停止后返回 nullptr
5. 当没有可用线程池时跳过缓存写入,避免产生悬空任务

Influence:
1. 验证正常使用下 SVG 图标仍能正确渲染并写入缓存文件
2. 测试在大量图标缓存任务排队时关闭应用,确保不会崩溃或出现线程已销毁的
警告
3. 确认不会在已销毁的 QCoreApplication 上运行任务,且无内存泄漏报告
4. 测试缓存文件的创建、提交和时间戳更新功能仍然正常
5. 验证从非主线程渲染 pixmap 时的行为(应跳过线程池)
6. 检查无缓存文件路径的图标仍能正常渲染,无回归问题
@18202781743
18202781743 force-pushed the fix-dsvgicon-cache-shutdown branch from c3e43c9 to 6b4b009 Compare September 11, 2026 09:25
@18202781743

Copy link
Copy Markdown
Contributor Author

@deepin-ci-robot

Copy link
Copy Markdown
Contributor

deepin pr auto review

🤖 AI 代码审查报告

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

Pass


📊 总体评价

项目 结果
审查结论 代码审查通过
评分详情 代码实现了一个应用拥有的线程池来解决 SVG 缓存任务在应用关闭后仍运行导致的崩溃问题,设计合理,实现正确,无安全漏洞。存在少量代码质量和性能优化建议。
漏洞对比统计 新增漏洞 0 个,减少漏洞 0 个,持平 0 个

📋 提交信息

项目 内容
PR #327 fix: prevent SVG cache tasks from outliving application
提交信息 fix: prevent SVG cache tasks outliving app
修改文件 iconengineplugins/svgiconengine/qsvgiconengine.cpp
变更行数 +49 / -1

🔍 详细分析

1. 语法逻辑 ✓

评价: 语法正确,逻辑清晰 ✓

评分: 25 / 25

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

分析说明:

  • 新增 IconCachePool 类继承自 QThreadPool,使用 final 关键字防止继承,语法正确
  • instance() 方法通过检查 QCoreApplication::instance() 和主线程身份,确保仅主线程可访问池实例,逻辑严密
  • aboutToQuit 信号处理顺序正确:先设置 stopped = true 阻止新任务,再 clear() 清除队列任务,最后 waitForDone() 等待活跃任务完成
  • QPointer<IconCachePool> 确保对象生命周期安全跟踪,防止应用销毁后悬空指针访问
  • C++11 静态局部变量初始化保证线程安全
  • stopped 标志虽为普通 bool 类型,但 instance() 已通过主线程检查确保对其的读写均在主线程执行,不存在数据竞争
  • instance() 返回 nullptr 时,run() 返回默认构造的 QFuture<void>(),调用方通过 Q_UNUSED(result) 忽略结果,逻辑正确

2. 代码质量 ✓

评价: 代码结构清晰,注释完整性有提升空间 ✓

评分: 23 / 25

潜在问题:

  1. iconengineplugins/svgiconengine/qsvgiconengine.cpp 第 42 行,IconCachePool 类:IconCachePool 类及关键方法 instance() 缺少注释,未说明为何需要检查主线程、为何使用 QPointerstopped 标志的设计意图等关键设计决策

建议:

  1. IconCachePool 类声明前添加类级注释,说明该线程池的设计目的和生命周期管理策略
  2. instance() 方法中添加注释说明主线程检查的必要性(确保 stopped 标志无线程安全问题)

3. 代码性能 ✓

评价: 性能良好,资源使用合理,存在一般优化空间 ✓

评分: 17 / 20

潜在问题:

  1. iconengineplugins/svgiconengine/qsvgiconengine.cpp 第 74 行,IconCachePool 构造函数 aboutToQuit lambda:waitForDone() 调用未设置超时时间。如果缓存写入任务因慢速磁盘 I/O、网络文件系统或文件锁竞争而卡住,将导致应用关闭被无限期阻塞。虽然 clear() 已清除队列中的待处理任务,但正在运行的任务仍会被无限制等待(由 OCR 专业代码审查工具发现)

建议:

  1. waitForDone() 改为 waitForDone(5000),设置合理的超时时间(如 5 秒),确保即使缓存写入缓慢,应用也能及时退出

修复代码示例:

// 修改前
connect(application, &QCoreApplication::aboutToQuit, this, [this] {
    stopped = true;
    clear();
    waitForDone();
});

// 修改后
connect(application, &QCoreApplication::aboutToQuit, this, [this] {
    stopped = true;
    clear();
    waitForDone(5000); // 最多等待 5 秒,防止极端情况下应用无法退出
});

4. 代码安全 ✓

评价: 存在0个安全漏洞 ✓

评分: 30 / 30

🔐 存在0个安全漏洞

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

分析说明:

  • 本次变更不涉及用户输入处理,无注入风险
  • 缓存文件路径由已有哈希逻辑生成,本次变更未修改
  • 线程池生命周期由 QCoreApplication 管理,无资源泄漏风险
  • QPointer 防止悬空指针访问,无内存安全问题

漏洞对比统计:新增漏洞 0 个,减少漏洞 0 个,持平 0 个


💡 总结

本次 PR 修复了 SVG 图标缓存写入任务在应用关闭后仍运行导致的崩溃问题。通过引入 IconCachePool(应用拥有的线程池),在 aboutToQuit 信号时正确停止接收新任务、清理队列、等待活跃任务完成,有效防止了 QFactoryLoader 崩溃。

代码设计合理,线程安全考虑周全,无安全漏洞。建议补充类级注释并为 waitForDone() 添加超时参数以增强健壮性。


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

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