Skip to content

fix: add QTemporaryDir::isValid() check to prevent silent failure - #389

Open
pengfeixx wants to merge 1 commit into
linuxdeepin:masterfrom
pengfeixx:agent/pms-bug-bot/352641fdb5df
Open

pengfeixx wants to merge 1 commit into
linuxdeepin:masterfrom
pengfeixx:agent/pms-bug-bot/352641fdb5df

Conversation

@pengfeixx

@pengfeixx pengfeixx commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

Root Cause Analysis

Two locations in deepin-reader use QTemporaryDir without checking isValid() after construction. When the TMPDIR environment variable points to a non-existent directory, QTemporaryDir silently fails — path() returns an empty string, and subsequent file operations use invalid paths without any error message or warning.

  • DjVuDocument::save() in reader/document/DjVuModel.cpp:795 — uses the empty path to construct a temp file path, causing saveAs() to operate on an invalid path.
  • DocSheet::convertedFileDir() in reader/uiframe/DocSheet.cpp:983 — returns the empty path to callers, causing subsequent file operations to silently fail.

Fix

Add isValid() check after QTemporaryDir creation in both locations. On failure, log a warning with errorString() and return an appropriate error value (false for save(), empty QString for convertedFileDir()).

Change Safety Assessment

Code Safety

  • Risk Level: Low
  • The change only adds a boundary check on the failure path; the normal execution path (when QTemporaryDir constructs successfully) is completely unchanged.
  • No signature changes, no memory leaks (failure path in convertedFileDir() properly deletes and nulls the pointer).

Business Impact Scope

Affects DjVu document saving and document format conversion (e.g., PDF export) features when TMPDIR is misconfigured. Users with a valid TMPDIR are unaffected.

Verification Suggestion

Test DjVu document save and document conversion/export with TMPDIR set to a non-existent directory — verify a warning is logged and the operation fails gracefully instead of silently producing invalid files.


根因分析

deepin-reader 中两处使用 QTemporaryDir 的代码在构造后未检查 isValid()。当 TMPDIR 环境变量指向不存在的目录时,QTemporaryDir 静默失败,path() 返回空字符串,后续文件操作使用无效路径,且无任何错误日志或警告。

  • DjVuDocument::save()reader/document/DjVuModel.cpp:795)— 使用空路径拼接临时文件路径,导致 saveAs() 在无效路径上执行。
  • DocSheet::convertedFileDir()reader/uiframe/DocSheet.cpp:983)— 返回空路径给调用方,导致后续文件操作静默失败。

修复方案

在两处 QTemporaryDir 创建后增加 isValid() 校验,失败时输出 qCWarning 日志并返回相应错误值(save() 返回 falseconvertedFileDir() 返回空 QString)。

改动安全评估

代码安全评估

  • 风险等级: 低
  • 改动仅在失败路径增加边界检查,正常执行路径(QTemporaryDir 构造成功时)完全不变。
  • 无签名变更,无内存泄漏(convertedFileDir() 失败路径正确释放并置空指针)。

业务影响范围

影响 TMPDIR 配置错误时的 DjVu 文档保存和文档格式转换(如 PDF 导出)功能。TMPDIR 正常的用户不受影响。

验证建议

TMPDIR 设为不存在的目录后测试 DjVu 文档保存和文档转换/导出功能——验证会输出警告日志并优雅失败,而非静默生成无效文件。

Summary by Sourcery

Fail gracefully and report errors when temporary directories cannot be created during document saving or conversion.

Bug Fixes:

  • Handle temporary-directory creation failures during DjVu saving and document conversion instead of continuing with invalid paths.
  • Log temporary-directory errors and return failure values when the configured temporary location is unavailable.

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: pengfeixx

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

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

Reviewer's Guide

The PR hardens DjVu saving and document conversion against invalid TMPDIR configurations by detecting QTemporaryDir creation failures, logging warnings with the underlying error, and returning failure values instead of continuing with empty paths; successful-path behavior is unchanged.

Sequence diagram for temporary directory validation during document operations

sequenceDiagram
    participant Caller
    participant DjVuDocument
    participant DocSheet
    participant QTemporaryDir
    participant FileOperation

    alt DjVuDocument::save()
        Caller->>DjVuDocument: save()
        DjVuDocument->>QTemporaryDir: isValid()
        alt temporary directory invalid
            DjVuDocument->>QTemporaryDir: errorString()
            DjVuDocument-->>Caller: false
        else temporary directory valid
            DjVuDocument->>QTemporaryDir: path()
            DjVuDocument->>FileOperation: saveAs(tempFilePath)
            FileOperation-->>Caller: save result
        end
    else DocSheet::convertedFileDir()
        Caller->>DocSheet: convertedFileDir()
        DocSheet->>QTemporaryDir: isValid()
        alt temporary directory invalid
            DocSheet->>QTemporaryDir: errorString()
            DocSheet-->>Caller: QString()
        else temporary directory valid
            DocSheet->>QTemporaryDir: path()
            DocSheet-->>Caller: temporary directory path
        end
    end
Loading

File-Level Changes

Change Details Files
Add explicit validation for temporary-directory creation before using its path.
  • Check QTemporaryDir::isValid() in DjVu saving and return false on failure.
  • Check the persistent conversion directory, log errorString(), clean up the invalid object, and return an empty path.
reader/document/DjVuModel.cpp
reader/uiframe/DocSheet.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

Prompt for AI Agents
Please address the comments from this code review:

## Individual Comments

### Comment 1
<location path="reader/uiframe/DocSheet.cpp" line_range="989" />
<code_context>
+        qCWarning(appLog) << "Failed to create temporary directory:" << m_tempDir->errorString();
+        delete m_tempDir;
+        m_tempDir = nullptr;
+        return QString();
+    }

</code_context>
<issue_to_address>
**issue (broader_impact):** The new empty-string failure result is not propagated by its callers: `openFileAsync()` and `openFileExec()` pass it to the renderer, while `saveAsData()` and `openedFilePath()` append filenames to it. This produces paths such as `/saveAsTemp.pdf` or `/temp.pdf`, so conversion and save operations still attempt invalid root-level paths instead of failing gracefully.

**Triggers:** When `QTemporaryDir` creation fails, such as with an invalid `TMPDIR`.

**Suggested fix:** Check the result of `convertedFileDir()` at each caller and abort before invoking the renderer or constructing a derived path; make `openedFilePath()` return an empty result when the conversion directory is unavailable.
</issue_to_address>

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

qCWarning(appLog) << "Failed to create temporary directory:" << m_tempDir->errorString();
delete m_tempDir;
m_tempDir = nullptr;
return QString();

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

issue (broader_impact): The new empty-string failure result is not propagated by its callers: openFileAsync() and openFileExec() pass it to the renderer, while saveAsData() and openedFilePath() append filenames to it. This produces paths such as /saveAsTemp.pdf or /temp.pdf, so conversion and save operations still attempt invalid root-level paths instead of failing gracefully.

Triggers: When QTemporaryDir creation fails, such as with an invalid TMPDIR.

Suggested fix: Check the result of convertedFileDir() at each caller and abort before invoking the renderer or constructing a derived path; make openedFilePath() return an empty result when the conversion directory is unavailable.

When TMPDIR environment variable points to a non-existent directory,
QTemporaryDir construction silently fails and path() returns an empty
string. Two locations were affected:

1. DjVuDocument::save() in reader/document/DjVuModel.cpp:795
   - save() used the empty path to construct a temp file path,
     causing saveAs() to operate on an invalid path.

2. DocSheet::convertedFileDir() in reader/uiframe/DocSheet.cpp:983
   - convertedFileDir() returned the empty path to callers,
     causing subsequent file operations to silently fail.

Fix: add isValid() check after QTemporaryDir creation in both
locations. On failure, log a warning with errorString() and return
an appropriate error value (false / empty QString).
@pengfeixx
pengfeixx force-pushed the agent/pms-bug-bot/352641fdb5df branch from 0c08cf6 to 3b516b0 Compare September 17, 2026 02:17
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

AI 代码审查报告

项目: linuxdeepin/deepin-reader
PR: #389
分支: agent/pms-bug-bot/352641fdb5df → master
提交: fix: add QTemporaryDir::isValid() check to prevent silent failure
分析模式: 全量分析(GitHub PR)
审查时间: 2026-09-17


总体评价

总分: 100/100
风险等级: None
总体结论: 代码审查通过

本次提交修复了 QTemporaryDir 在 TMPDIR 环境变量指向不存在目录时静默失败的问题。在两处位置(DjVuDocument::save() 和 DocSheet::convertedFileDir())添加了 isValid() 检查,在临时目录创建失败时记录警告日志并返回适当的错误值。代码实现与 commit message 描述的修复目的完全一致,修改小而聚焦,逻辑清晰,无安全风险。


漏洞统计

指标 数量
当前漏洞总数 0
新增漏洞 0
修复漏洞 0
持平漏洞 0

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


四维度评分

维度1: 语法逻辑 ✓ (25/25)

语法正确,逻辑清晰

分析:

  1. 新增代码完全符合 C++ 语法规范,无编译错误风险
  2. DjVuDocument::save() (reader/document/DjVuModel.cpp:796-799): 在 QTemporaryDir 创建后添加 isValid() 检查,失败时返回 false,逻辑正确
  3. DocSheet::convertedFileDir() (reader/uiframe/DocSheet.cpp:985-990): 在 QTemporaryDir 创建后添加 isValid() 检查,失败时正确清理内存(delete + nullptr)并返回空 QString
  4. 两处修改的边界条件处理完善:栈对象直接返回 false,堆对象先清理再返回空值

问题:

维度2: 代码质量 ✓ (25/25)

代码结构清晰,注释完整

分析:

  1. 注释完整性: qCWarning 日志提供了清晰的错误信息,包含 tempDir.errorString() 返回的具体失败原因,便于问题诊断
  2. 代码重复: 两处代码虽然模式相似(检查 isValid + 记录日志 + 返回错误值),但上下文不同——DjVuModel.cpp 中 tempDir 是栈对象,DocSheet.cpp 中 m_tempDir 是堆对象需要额外的内存清理。这不属于不合理的代码重复
  3. 结构合理性: 修改小而聚焦,每个函数只增加了必要的验证逻辑,未引入过长的函数体或复杂的控制流
  4. 调试信息清理: qCWarning 是警告级别的日志输出,用于记录错误情况,属于合理的错误处理日志,符合 commit message 中"log a warning with errorString()"的目的,非残留调试代码

问题:

维度3: 代码性能 ✓ (20/20)

性能良好,资源使用合理

分析:

  1. QTemporaryDir::isValid() 是轻量级的内部状态检查操作,无性能开销
  2. 提前返回(fail-fast)模式在错误情况下避免了不必要的后续文件操作(如 saveAs、路径拼接等),实际上提升了错误场景下的性能
  3. 无不必要的拷贝、字符串拼接或容器操作
  4. 无性能瓶颈

问题:

维度4: 代码安全 ✓ (30/30)

存在0个安全漏洞

分析:

  1. 无安全漏洞:本次修改未引入任何安全风险
  2. 安全性增强:此修复实际上增强了安全性——防止了在无效路径上执行文件操作,避免了可能导致文件写入到意外位置的风险
  3. 无硬编码密钥、无敏感信息泄露
  4. 无命令注入、SQL注入、路径遍历等风险
  5. 无用户输入未校验的问题

问题:


修改文件清单

文件 修改内容
reader/document/DjVuModel.cpp DjVuDocument::save() 添加 QTemporaryDir::isValid() 检查
reader/uiframe/DocSheet.cpp DocSheet::convertedFileDir() 添加 QTemporaryDir::isValid() 检查及内存清理

代码变更详情

reader/document/DjVuModel.cpp (DjVuDocument::save(), 第796-799行)

QTemporaryDir tempDir;
if (!tempDir.isValid()) {
    qCWarning(appLog) << "Failed to create temporary directory:" << tempDir.errorString();
    return false;
}

评价: 在栈上创建 QTemporaryDir 后立即检查有效性,失败时记录警告并返回 false,防止后续在空路径上执行 saveAs() 操作。处理方式简洁正确。

reader/uiframe/DocSheet.cpp (DocSheet::convertedFileDir(), 第985-990行)

if (!m_tempDir->isValid()) {
    qCWarning(appLog) << "Failed to create temporary directory:" << m_tempDir->errorString();
    delete m_tempDir;
    m_tempDir = nullptr;
    return QString();
}

评价: 在堆上创建 QTemporaryDir 后检查有效性,失败时记录警告、清理内存(delete + nullptr)并返回空 QString。内存清理确保下次调用时可重新创建临时目录,处理方式正确。


审查结论

本次提交是一个高质量的 bug 修复,代码实现与 commit message 描述的目的完全一致。修改在两处关键位置添加了 QTemporaryDir::isValid() 检查,防止了临时目录创建失败时的静默错误行为。代码逻辑正确、结构清晰、无安全风险,建议合并。


本报告由 AI 代码审查系统自动生成
审查模型: oneai
审查时间: 2026-09-17

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