Skip to content

test(editor): fix heap-buffer-overflow crash in UT_Editwrapper_loadContent - #509

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
pengfeixx:fix/ut-editwrapper-loadcontent-crash
Aug 7, 2026
Merged

test(editor): fix heap-buffer-overflow crash in UT_Editwrapper_loadContent#509
deepin-bot[bot] merged 1 commit into
linuxdeepin:masterfrom
pengfeixx:fix/ut-editwrapper-loadcontent-crash

Conversation

@pengfeixx

@pengfeixx pengfeixx commented Aug 7, 2026

Copy link
Copy Markdown
Contributor

Problem

Running the deepin-editor unit tests with ASan+UBSan aborted the whole test process at UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_001:

==492409==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504008a22872
READ of size 12 at 0x504008a22872 thread T0
    #0 __interceptor_memcpy
    #1 QString::append(QChar const*, int)
    #2 QDebug::putString(QChar const*, unsigned long)
    #3 QDebug::operator<<(QString const&)            qdebug.h:161
    #4 DDropdownMenu::setText(QString const&)         src/widgets/ddropdownmenu.cpp:214
    #5 DDropdownMenu::setCurrentTextOnly(QString const&)
    #6 BottomBar::setEndlineMenuText(BottomBar::EndlineFormat)  src/widgets/bottombar.cpp:436
    #7 EditWrapper::loadContent(QByteArray const&)    src/editor/editwrapper.cpp:1700
    #8 UT_Editwrapper_loadContent_001_Test::TestBody() tests/src/editor/ut_editwrapper.cpp:1388
...
==492409==ABORTING

Root cause

UT_Editwrapper_loadContent_001/002 installed a global stub that made QString::length() return a very large value (41 * 1024 * 1024 / 10 * 1024):

Stub s1;
s1.set(ADDR(QString,length),retintstub);
intvalue = 41*1024*1024;
wra->loadContent("ddd");

This was both ineffective and harmful:

  • EditWrapper::loadContent() decides the branch from int len = strContent.length();, and strContent is a QByteArray. Stubbing QString::length therefore never influenced the branch selection — len always stayed the real size of "ddd".
  • QString::length() is an out-of-line symbol in libQt5Core, so the stub globally corrupted every QString::length() call in the whole process. QDebug::operator<<(const QString&) (qdebug.h:161) is putString(t.constData(), uint(t.length())), so when DDropdownMenu::setText() later printed the endline menu text ("Unix") via qDebug(), it tried to append 41M characters from a tiny string buffer, reading past the end of the heap allocation and aborting under ASan.

Fix

Stub QByteArray::length instead — the real type of strContent:

s1.set(ADDR(QByteArray,length),retintstub);

This makes loadContent() actually take the intended large-file / instant-open branches. It is safe because:

  • qDebug() prints a QByteArray through size() (not length()), and prints a QString through QString::length() which is no longer stubbed — so no out-of-bounds read is introduced.
  • The actual data reads inside loadContent() / customEvent() use size() / d->size (e.g. codec->toUnicode(..., text.size(), ...), QByteArray::mid()) rather than length(), so the large stubbed length only drives the loop/branch control flow, never a data copy.

Verification

Built with the project's UT configuration (-DCMAKE_BUILD_TYPE=Debug -DCMAKE_SAFETYTEST_ARG=CMAKE_SAFETYTEST_ARG_ON, which enables -fsanitize=undefined,address):

$ ./tests/deepin-editor-test --gtest_filter='UT_Editwrapper_loadContent.*'
[ RUN      ] UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_001
[       OK ] UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_001 (1299 ms)
[ RUN      ] UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_002
[       OK ] UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_002 (171 ms)
[==========] 2 tests from 1 test suite ran.
[  PASSED  ] 2 tests.

No heap-buffer-overflow, no ABORTING. The full UT_Editwrapper_* suite shows no regressions; the remaining UT_Editwrapper_saveFile_004/005, UT_Editwrapper_saveAsFile_003 and UT_Editwrapper_handleFileLoadFinished_004_error failures are pre-existing (they already fail on master before this change) and unrelated to this crash.

Summary by Sourcery

Adjust EditWrapper loadContent unit tests to stub the correct QByteArray length API and document the rationale to prevent sanitizer-detected crashes.

Bug Fixes:

  • Fix heap-buffer-overflow in UT_Editwrapper_loadContent tests caused by globally stubbing QString::length instead of the QByteArray length used by loadContent.

Tests:

  • Update UT_Editwrapper_loadContent_001 and _002 to stub QByteArray::length instead of QString::length and add inline documentation explaining the safe stubbing behavior.

…ntent

UT_Editwrapper_loadContent_001/002 stubbed QString::length to a large
value (41MB/10KB) in order to drive EditWrapper::loadContent into its
large-file and instant-open branches. This was both ineffective and
harmful:

- loadContent() reads the content size from strContent.length(), and
  strContent is a QByteArray, so stubbing QString::length never affected
  the branch selection.
- QString::length() is an out-of-line symbol in libQt5Core, so the stub
  globally corrupted every QString::length() call in the process.
  QDebug::operator<<(const QString&) (qdebug.h) calls t.length(), which
  made qDebug read far past the string buffer. This triggered an ASan
  heap-buffer-overflow (READ of size 12) and aborted the whole test
  process when DDropdownMenu::setText() printed the endline menu text
  ("Unix") via BottomBar::setEndlineMenuText() -> setCurrentTextOnly()).

Fix: stub QByteArray::length instead -- the real type of strContent, so
loadContent() now takes the intended large-file / instant-open branches.
This is safe because qDebug prints a QByteArray via size() (not length())
and the actual data reads in loadContent()/customEvent() use size()/d->size
rather than length(), so no out-of-bounds read is introduced.

Verified with an ASan+UBSan build:
  UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_001  -> OK
  UT_Editwrapper_loadContent.UT_Editwrapper_loadContent_002  -> OK
No heap-buffer-overflow; the 4 other pre-existing UT_Editwrapper failures
are unchanged and unrelated to this crash.

@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 @pengfeixx, you have reached your weekly rate limit of 500000 diff characters.

Please try again later or upgrade to continue using Sourcery

@sourcery-ai

sourcery-ai Bot commented Aug 7, 2026

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

Reviewer's Guide

Adjusts the EditWrapper loadContent unit tests to stub QByteArray::length instead of QString::length, preventing a global corruption of QString length calls that led to an ASan-detected heap-buffer-overflow, and documents the rationale in-code.

File-Level Changes

Change Details Files
Fix loadContent unit tests to stub the correct length function and avoid ASan heap-buffer-overflow in qDebug/QString usage.
  • Update UT_Editwrapper_loadContent_001 to stub QByteArray::length instead of QString::length so the fake size affects EditWrapper::loadContent’s control flow without impacting QString globally.
  • Update UT_Editwrapper_loadContent_002 to use the same QByteArray::length stub, ensuring consistent behavior for both large-file branches.
  • Add detailed comments in both tests explaining why QString::length stubbing was unsafe and why QByteArray::length is safe and correct for this scenario.
tests/src/editor/ut_editwrapper.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

★ 总体评分:100分

■ 【总体评价】

代码准确修复了单元测试中因错误Stub导致的堆缓冲区溢出问题,注释详尽
逻辑完全正确且注释充分,无扣分项

■ 【详细分析】

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

修复前错误地Stub了QString::length,导致QDebug::operator<<(const QString&)内部调用t.length()时读取越界,触发heap-buffer-overflow。修复后正确地将Stub目标更正为QByteArray::length,因为loadContent()内部实际通过QByteArray的length()判断文件大小,逻辑完全正确。
潜在问题:无
建议:无

  • 2.代码质量(优秀)✓

增加了长达7行和3行的详细注释,精准解释了为什么不能Stub QString::length(会破坏全局QString操作导致越界),以及为什么Stub QByteArray::length是安全的(QDebug打印QByteArray走size()路径,实际数据读取也用size()/d->size),极大提升了代码的可维护性。
潜在问题:无
建议:无

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

此代码为单元测试中的Stub设置,仅影响测试执行期的函数调用指向,对生产环境代码性能无任何影响。
建议:无

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

漏洞对比统计:新增漏洞 0 个,减少漏洞 1 个,持平 0 个
本次修改成功修复了原测试代码中存在的堆缓冲区溢出缺陷,消除了因全局QString长度被篡改而引发的内存越界读取风险。当前测试代码不再引发内存破坏,无新增安全漏洞。

  • 建议:继续保持对Mock/Stub对象作用域的精确控制,避免对基础类型(如QString)的全局方法进行Hook。

■ 【改进建议代码示例】

// 当前代码已为最佳实践,无需进一步修改,以下为当前正确实现的重申
// loadContent() determines the file size via `strContent.length()` where
// strContent is a QByteArray, so the size must be faked on QByteArray, not
// QString. Stubbing QString::length globally corrupts every QString in the
// process: QDebug::operator<<(const QString&) (qdebug.h) calls t.length(),
// which then makes qDebug read past the string buffer and triggers a
// heap-buffer-overflow (e.g. when DDropdownMenu::setText prints the endline
// text). QByteArray::length is safe to stub here because qDebug prints a
// QByteArray through size() and the actual data reads in loadContent use
// size()/d->size rather than length().
Stub s1;
s1.set(ADDR(QByteArray,length),retintstub);

intvalue = 41*1024*1024;
wra->loadContent("ddd");

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: lzwind, 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

@pengfeixx

Copy link
Copy Markdown
Contributor Author

/merge

@deepin-bot
deepin-bot Bot merged commit 8bcfbd9 into linuxdeepin:master Aug 7, 2026
20 checks passed
@pengfeixx
pengfeixx deleted the fix/ut-editwrapper-loadcontent-crash branch August 7, 2026 01:45
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