semantic search#329
Conversation
Johnson-zs
commented
Jun 26, 2026
- fix(dfm-io): drain GLib deferred callbacks after g_file_enumerate_children
- fix(dfm-io): close FTS tree in destructor to prevent memory leak
- perf(dfm-io): cache statx results in DFileInfoPrivate::attributesBySelf
- fix: prevent BOM character loss in path concatenation
…ldren g_file_enumerate_children() internally creates and destroys temporary GDBusProxy instances (mount tracker proxy, daemon proxy) whose finalization defers the weak_ref_free callback to the thread-default GMainContext via call_destroy_notify() as a g_idle_source. In a QThread without a GLib main loop, these idle sources are never dispatched, causing the GWeakRef allocations (8 bytes each from gdbusproxy.c:112) to leak. Iterate the thread-default GMainContext immediately after the GVFS enumeration call to process the deferred callbacks while still on the same thread. Log: Fixed 8-byte GWeakRef memory leak triggered by GVFS trash enumeration. Assisted-by: deepseek-v4-pro Influence: 1. Enumerate trash:/// under Valgrind — verify zero definitely-lost bytes at weak_ref_new 2. Test trash directory traversal with daemon running and file manager not in background 3. Verify normal file enumeration (local paths) is unaffected 4. Verify enumerate with timeout (QtConcurrent path) is unaffected 5. Verify rapid open/close of trash window does not accumulate leaks fix(dfm-io): 在 g_file_enumerate_children 后处理 GLib 延迟回调,修复 GWeakRef 泄露 g_file_enumerate_children() 内部会创建并销毁临时的 GDBusProxy 实例 (mount tracker proxy 和 daemon proxy),其析构时通过 call_destroy_notify() 将 weak_ref_free 回调以 g_idle_source 的形式 挂载到线程默认的 GMainContext。在没有 GLib 主循环的 QThread 中, 这些 idle source 永远不会被调度,导致 GWeakRef 分配(每次 8 字节, 来自 gdbusproxy.c:112)泄露。 在 GVFS 枚举调用返回后立即迭代线程默认的 GMainContext, 在同一个线程上处理延迟回调,避免泄露。 Log: 修复 GVFS 回收站枚举时触发的 8 字节 GWeakRef 内存泄露。 Influence: 1. Valgrind 下枚举 trash:/// — 验证 weak_ref_new 处零 definitely lost 2. 测试 daemon 运行且文件管理器未驻留时回收站目录遍历 3. 验证普通本地文件枚举不受影响 4. 验证带超时的枚举(QtConcurrent 路径)不受影响 5. 验证快速打开/关闭回收站窗口不累积泄露
When initEnumerator(false) is called, openDirByfts() allocates an FTS tree via fts_open(). However, LocalDirIterator::sortFileInfoList() uses its own opendir()/readdir()/closedir() implementation and never calls fts_close(), leaving the FTS tree (5,279 bytes including indirect allocations) leaked. Close the FTS tree in the destructor as a safety net so it is always freed regardless of which sortFileInfoList() code path is taken. Log: Fixed FTS tree memory leak when LocalDirIterator bypasses fts_close(). Assisted-by: deepseek-v4-pro Influence: 1. Open a local directory with dde-file-manager - verify no fts_open leak under Valgrind 2. Test batch directory traversal with sort role set (sortFileInfoList path) 3. Verify one-by-one enumeration path is unaffected 4. Test vault and SMB directory traversal paths 5. Verify rapid open/close of file manager window does not accumulate fts_open leaks fix(dfm-io): 在析构函数中关闭 FTS 树以防止内存泄露 initEnumerator(false) 调用 openDirByfts() 通过 fts_open() 分配 FTS 树,但 LocalDirIterator::sortFileInfoList() 使用自己的 opendir()/readdir()/closedir() 实现,从未调用 fts_close(), 导致 FTS 树(含间接分配共 5,279 字节)泄露。 在析构函数中添加 fts_close() 作为安全兜底,确保无论走哪个 sortFileInfoList() 代码路径,FTS 树都能被释放。 Log: 修复 LocalDirIterator 绕过 fts_close() 导致的 FTS 树内存泄露。 Influence: 1. 使用 dde-file-manager 打开本地目录 — Valgrind 下验证 fts_open 无泄露 2. 测试设置排序角色后的批量目录遍历(sortFileInfoList 路径) 3. 验证逐个遍历路径不受影响 4. 测试保险箱和 SMB 目录遍历路径 5. 验证快速打开/关闭文件管理器窗口不累积 fts_open 泄露
Introduce ensureStatxCached() to consolidate six independent statx syscalls into one. Cache the result in mutable member fields so that subsequent time-attribute queries reuse the same buffer. 在 attributesBySelf 中引入 ensureStatxCached() 方法,将 6 个时间 属性的重复 statx 系统调用合并为一次,结果缓存后各 case 直接读取。 Log: 优化 attributesBySelf 中 statx 调用,消除重复系统调用 Task: https://pms.uniontech.com/task-view-391003.html Influence: 查询 kTimeCreated/Modified/Access 等属性时,statx 从最多 6 次降为 1 次,减少不必要的系统调用开销。
Use std::string for directory path concatenation to avoid QString's normalization of UTF-8 BOM (U+FEFF / zero-width no-break space). 使用 std::string 进行路径拼接,避免 QString 对 UTF-8 BOM (零宽不换行空格) 的规范化导致字节丢失。 Log: 修复路径拼接时 BOM 字符丢失的问题 Bug: https://pms.uniontech.com//bug-view-367075.html Influence: 修复后包含 BOM/零宽不换行空格的路径能正确拼接,避免文件操作失败。
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: Johnson-zs The full list of commands accepted by this bot can be found here. DetailsNeeds approval from an approver in each of these files:Approvers can indicate their approval by writing |
There was a problem hiding this comment.
Sorry @Johnson-zs, you have reached your weekly rate limit of 500000 diff characters.
Please try again later or upgrade to continue using Sourcery
deepin pr auto review★ 总体评分:100分■ 【总体评价】
■ 【详细分析】
■ 【改进建议代码示例】 // 文件:denumerator.cpp buildUrl()
// 建议增加对空字节截断攻击的防御,使安全防护更加严密
QUrl DEnumeratorPrivate::buildUrl(const QUrl &url, const char *fileName)
{
// 防御空指针,避免std::string或QByteArray构造时崩溃
if (!fileName) {
return QUrl();
}
QByteArray fileNameBa(fileName);
// 防御空字节截断攻击,防止类似 "file.txt\0.exe" 的恶意绕过
if (fileNameBa.contains('\0')) {
return QUrl();
}
// 拦截路径遍历攻击,防止恶意文件名越权
if (fileNameBa.contains('/') || fileNameBa.contains('\\') || fileNameBa == "." || fileNameBa == "..") {
return QUrl();
}
QByteArray path;
QString urlPath = url.path();
if (urlPath == "/" || urlPath.isEmpty()) {
path = QByteArray("/") + fileNameBa;
} else {
QByteArray dirPath = urlPath.toUtf8();
if (!dirPath.endsWith('/')) {
dirPath.append('/');
}
// 使用QByteArray进行底层字节数组拼接,避免QString剥离BOM (efbbbf)
path = dirPath + fileNameBa;
}
// 保留原始 URL 的 scheme 和 host,而不是假定为本地文件
QUrl newUrl(url);
newUrl.setPath(QString::fromUtf8(path));
return newUrl;
} |