Skip to content

fix(utils): avoid command string concatenation in lookup#857

Merged
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
tianming-1996:release/eagle
Jun 2, 2026
Merged

fix(utils): avoid command string concatenation in lookup#857
deepin-bot[bot] merged 1 commit into
linuxdeepin:release/eaglefrom
tianming-1996:release/eagle

Conversation

@tianming-1996

Copy link
Copy Markdown

Use QProcess arguments instead of building a command string.

使用QProcess参数列表替代命令字符串拼接。

Log: 修复命令查找逻辑中的字符串拼接风险
Task:https://pms.uniontech.com/task-view-390623.html Influence: 仅影响dman命令存在性检查逻辑,F1帮助快捷键行为保持不变。

Use QProcess arguments instead of building a command string.

使用QProcess参数列表替代命令字符串拼接。

Log: 修复命令查找逻辑中的字符串拼接风险
Task:https://pms.uniontech.com/task-view-390623.html
Influence: 仅影响dman命令存在性检查逻辑,F1帮助快捷键行为保持不变。
@deepin-ci-robot

Copy link
Copy Markdown

deepin pr auto review

你好!我是CodeGeeX。我已仔细审查了你提供的 Git Diff 输入。这次代码修改整体上是一次非常优秀的重构,修复了原代码中存在的多个严重问题。以下是详细的审查意见:

一、 整体评价

这次修改将原本基于堆分配(new)的 QProcess 改为了栈分配,并使用了更安全的 QStringList 参数传递方式,避免了命令注入风险和潜在的内存泄漏。代码变得更加简洁、安全、高效。

二、 优点分析(改进点)

  1. 消除内存泄漏风险(代码质量/安全)

    • 旧代码:使用了 new QProcess,虽然后面有 delete proc,但如果 proc->waitForFinished(1000) 抛出异常或在未来代码修改中提前 return,就会导致内存泄漏。
    • 新代码:使用栈对象 QProcess proc;,利用 RAII(资源获取即初始化)机制,函数结束时无论以何种方式退出,都会自动销毁对象,彻底消除了内存泄漏的隐患。同时,旧代码中对 !proc 的判断在现代 C++ 中是多余的(除非重载了 new 并返回 nullptr,或者抛出 std::bad_alloc),新代码也合理地去掉了这一冗余检查。
  2. 修复命令注入漏洞(代码安全)

    • 旧代码QString("which %1\n").arg(command) 将用户输入直接拼接到字符串中执行。如果 command 是恶意字符串(例如 "ls; rm -rf /"),则会引发命令注入攻击。
    • 新代码proc.start(QStringLiteral("which"), QStringList() << command); 使用了参数列表传递。QProcess 会将 QStringList 中的每个参数作为独立的参数传递给目标程序,即使 command 包含特殊字符(如 ;&、空格等),也会被当作普通字符串处理,从根本上杜绝了命令注入的风险。
  3. 去除不必要的换行符(语法逻辑)

    • 旧代码:字符串末尾带有 \n,这在 QProcess::start() 中是不必要的,甚至可能在某些底层系统调用中引发不可预期的行为。
    • 新代码:移除了 \n,逻辑更加严谨。
  4. 性能与编译期优化(代码性能)

    • 新代码:使用了 QStringLiteral("which"),这会在编译期构建 QString 数据结构,避免了运行时的内存分配和编码转换,提升了性能。
  5. 代码简洁性(代码质量)

    • 旧代码int ret = proc->exitCode() == 0; return ret; 存在隐式类型转换(boolint 再隐式转回 bool)。
    • 新代码:直接 return proc.exitCode() == 0;,语义清晰,没有冗余转换。

三、 进一步改进建议

虽然新代码已经很好了,但仍有几个细节可以继续优化,以应对生产环境下的极端情况:

1. 关于 which 命令的跨平台兼容性(代码逻辑/质量)

which 命令在绝大多数 Linux/Unix/macOS 系统上可用,但在 Windows 环境下不存在(Windows 下对应的是 where)。如果你的项目需要跨平台,建议做如下改进:

bool BaseUtils::isCommandExist(const QString &command)
{
    QProcess proc;
#ifdef Q_OS_WIN
    proc.start(QStringLiteral("where"), QStringList() << command);
#else
    proc.start(QStringLiteral("which"), QStringList() << command);
#endif
    proc.waitForFinished(1000);
    return proc.exitCode() == 0;
}

2. 处理 waitForFinished 超时与进程状态(代码逻辑/健壮性)

如果 1 秒后进程仍未结束(例如系统负载极高或挂起),waitForFinished(1000) 会返回 false,但此时进程仍在后台运行。后续调用 exitCode() 可能会返回无效值,且该子进程可能会变成僵尸进程或导致资源泄漏。建议在超时后主动终止进程:

bool BaseUtils::isCommandExist(const QString &command)
{
    QProcess proc;
    proc.start(QStringLiteral("which"), QStringList() << command);
    
    if (!proc.waitForFinished(1000)) {
        proc.kill(); // 超时后强制终止进程
        proc.waitForFinished(); // 等待进程清理完毕
        return false;
    }
    
    return proc.exitCode() == 0;
}

3. 函数参数建议使用 const &(代码性能)

传入的 QString command 会发生一次拷贝构造。对于 QString 这种隐式共享的类,拷贝开销虽然不大,但作为良好的编程习惯,对于只读参数应尽量使用 const QString &

bool BaseUtils::isCommandExist(const QString &command) // 添加 const &

四、 最终推荐代码

综合以上建议,推荐的安全、健壮、跨平台版本如下:

bool BaseUtils::isCommandExist(const QString &command)
{
    QProcess proc;
#ifdef Q_OS_WIN
    proc.start(QStringLiteral("where"), QStringList() << command);
#else
    proc.start(QStringLiteral("which"), QStringList() << command);
#endif

    if (!proc.waitForFinished(1000)) {
        proc.kill();
        proc.waitForFinished();
        return false;
    }

    return proc.exitCode() == 0;
}

总结:你的原始修改已经非常出色,解决了最核心的内存泄漏和命令注入问题。如果项目仅针对 Linux 平台且对超时容忍度较高,你当前的 Diff 代码已经完全符合生产标准;若追求更高的健壮性,可参考上述进一步改进建议。

@deepin-ci-robot

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by: max-lvs, tianming-1996

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

@tianming-1996

Copy link
Copy Markdown
Author

/merge

@deepin-bot deepin-bot Bot merged commit c1c1037 into linuxdeepin:release/eagle Jun 2, 2026
7 checks passed
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