Skip to content

refactor: Replace popen with QProcess for process count and kill oper…#421

Merged
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
LiHua000:release/eagle
Feb 11, 2026
Merged

refactor: Replace popen with QProcess for process count and kill oper…#421
deepin-bot[bot] merged 1 commit intolinuxdeepin:release/eaglefrom
LiHua000:release/eagle

Conversation

@LiHua000
Copy link

@LiHua000 LiHua000 commented Feb 11, 2026

…ations

  • Updated getProcessCountByName to use QProcess for executing the ps command, improving reliability and handling of process output.
  • Refactored killProcessByName to utilize QProcess for killing processes, enhancing code consistency and error handling.
  • Improved null and empty string checks for process names in both functions.

This change enhances the maintainability and performance of process management in the application.

Summary by Sourcery

Refactor process management utilities to use Qt's QProcess instead of C library process APIs.

Enhancements:

  • Replace popen and system calls in process counting and killing utilities with QProcess-based implementations for better integration and reliability.
  • Add debug logging around process counting and killing operations to aid diagnostics.
  • Tighten null and empty string validation for process names in utility functions to prevent invalid invocations.

…ations

- Updated `getProcessCountByName` to use `QProcess` for executing the `ps` command, improving reliability and handling of process output.
- Refactored `killProcessByName` to utilize `QProcess` for killing processes, enhancing code consistency and error handling.
- Improved null and empty string checks for process names in both functions.

This change enhances the maintainability and performance of process management in the application.
@sourcery-ai
Copy link

sourcery-ai bot commented Feb 11, 2026

Reviewer's Guide

Refactors process management utilities to use Qt's QProcess instead of popen/system, adds basic logging, and tightens null/empty checks for process names.

Sequence diagram for getProcessCountByName refactor using QProcess

sequenceDiagram
    participant Caller
    participant Utils
    participant QProcess

    Caller->>Utils: getProcessCountByName(pstrName)
    Utils->>Utils: check pstrName null or empty
    alt invalid_name
        Utils-->>Caller: return -1
    else valid_name
        Utils->>QProcess: start(ps, [-ef])
        QProcess-->>Utils: started
        Utils->>QProcess: waitForFinished(5000)
        alt timeout
            Utils-->>Caller: return -1
        else finished
            Utils->>QProcess: readAllStandardOutput()
            QProcess-->>Utils: output
            Utils->>Utils: split output by newline
            Utils->>Utils: count lines containing processName
            Utils-->>Caller: return count
        end
    end
Loading

Sequence diagram for killProcessByName refactor using QProcess

sequenceDiagram
    participant Caller
    participant Utils
    participant QProcess

    Caller->>Utils: killProcessByName(pstrName)
    Utils->>Utils: check pstrName null or empty
    alt invalid_name
        Utils-->>Caller: return
    else valid_name
        Utils->>QProcess: start(killall, [processName])
        QProcess-->>Utils: started
        Utils->>QProcess: waitForFinished(5000)
        QProcess-->>Utils: finished
        Utils-->>Caller: return
    end
Loading

Class diagram for Utils process management refactor

classDiagram
    class Utils {
        +int getProcessCountByName(const char * pstrName)
        +void killProcessByName(const char * pstrName)
    }

    class QProcess {
        +void start(QString program, QStringList arguments)
        +bool waitForFinished(int msecs)
        +QByteArray readAllStandardOutput()
    }

    Utils ..> QProcess : uses
Loading

File-Level Changes

Change Details Files
Refactor getProcessCountByName to use QProcess and manual parsing of ps output instead of popen with a shell pipeline.
  • Replace popen-based "ps -ef
grep ...
Refactor killProcessByName to use QProcess running killall instead of composing a shell command and calling system().
  • Replace system("killall ...") call with QProcess that starts the killall executable with the process name as an argument
  • Add early-return validation for null or empty process names with qDebug logging
  • Introduce entry/exit debug logs and wait for the killall process to finish with a 5-second timeout
src/common/utils.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

[APPROVALNOTIFIER] This PR is NOT APPROVED

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

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

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

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

Hey - I've left some high level feedback:

  • The new getProcessCountByName implementation may overcount because it blindly counts any ps -ef line containing the name (e.g., header line or unrelated arguments); consider filtering out the header and matching on the executable column or with a stricter pattern.
  • Both getProcessCountByName and killProcessByName now use QProcess but ignore its exit code and error state; checking process.exitStatus() / process.error() and logging failures would make the behavior more predictable and debuggable.
  • The added qDebug() calls in these utility functions might be noisy in production or performance‑sensitive paths; consider guarding them with a debug flag or reducing verbosity.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- The new `getProcessCountByName` implementation may overcount because it blindly counts any `ps -ef` line containing the name (e.g., header line or unrelated arguments); consider filtering out the header and matching on the executable column or with a stricter pattern.
- Both `getProcessCountByName` and `killProcessByName` now use `QProcess` but ignore its exit code and error state; checking `process.exitStatus()` / `process.error()` and logging failures would make the behavior more predictable and debuggable.
- The added `qDebug()` calls in these utility functions might be noisy in production or performance‑sensitive paths; consider guarding them with a debug flag or reducing verbosity.

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

@deepin-ci-robot
Copy link

deepin pr auto review

这段代码主要重构了两个函数:getProcessCountByNamekillProcessByName,将原来使用 C 风格的 popen/system 改为了 Qt 框架下的 QProcess

总体来说,重构方向是正确的,使用 QProcesspopen/system 更安全、更易移植,且能更好地处理进程超时和输出。但在实现细节上,特别是 getProcessCountByName 函数的逻辑,存在一些问题和优化空间。

以下是详细的审查意见:

1. 语法逻辑与功能正确性

主要问题:getProcessCountByName 逻辑缺失

  • 问题描述:原代码使用了 grep -v grep,目的是在统计进程数时排除掉 grep 命令自身的进程(因为 ps -ef | grep name 这条命令本身也会出现在进程列表中)。
  • 当前代码缺陷:新代码简单地遍历 ps -ef 的输出并检查是否包含进程名。如果进程名很短(例如 "a"),或者恰好匹配了 ps 命令参数中的其他字段,会导致统计错误。更重要的是,如果调用这个函数的进程自身名字也包含 pstrName,或者系统中存在无关进程包含该字符串,都会被错误统计。
  • 改进建议
    • 在遍历每一行时,应解析 ps -ef 的输出格式。ps -ef 的输出通常格式为:UID PID PPID C STIME TTY TIME CMD
    • 我们应该只检查 CMD(命令行)字段是否完全匹配或以目标进程名开头。
    • 排除自身:通常需要获取当前进程的 PID(QCoreApplication::applicationPid()),在统计时排除掉当前 PID,以防止逻辑死锁或误判。

2. 代码质量

  • 日志输出:增加了 qDebug() 输出,这对于调试很有帮助。但在生产环境中,高频调用的函数打印大量日志可能会影响性能。建议考虑使用条件编译(如 QT_DEBUG)或日志等级控制。
  • 字符串处理:使用了 QString::fromUtf8(pstrName),这是好的做法,确保了编码的一致性。
  • 硬编码超时waitForFinished(5000) 写死了 5 秒。建议将其定义为常量或宏,以便统一管理。

3. 代码性能

  • ps -ef 的开销:调用 ps -ef 会列出系统所有进程,如果系统进程很多,输出字符串会非常大,split('\n') 会产生大量的 QString 对象,造成内存分配和 CPU 消耗。
  • 改进建议
    • 如果只是查找特定进程,可以使用 ps -C <name> (Linux) 或 pgrep 命令(如果系统允许),这通常比在用户空间过滤全量列表要快。
    • 如果必须解析 ps 输出,建议在读取流式输出时逐行处理,而不是 readAllStandardOutput() 后一次性处理,以减少内存峰值。

4. 代码安全

  • 命令注入风险 (已修复)
    • 原代码使用 sprintf 构造 shell 命令字符串,如果 pstrName 包含 ; rm -rf /$(evil_cmd) 等字符,会导致严重的命令注入漏洞。
    • 新代码使用 QProcess::start(const QString &program, const QStringList &arguments),参数是以列表形式传递的,完全规避了 Shell 解析,消除了命令注入风险。这是本次重构最大的安全亮点。
  • 空指针检查
    • killProcessByName 中增加了 if (pstrName == NULL ...) 检查,这是正确的。原代码虽然也有检查,但新代码逻辑更清晰。

改进后的代码示例

针对 getProcessCountByName 的逻辑缺陷和性能问题,建议修改如下:

#include <QCoreApplication>
#include <QProcess>
#include <QStringList>

int Utils::getProcessCountByName(const char *pstrName)
{
    // 1. 参数校验
    if (NULL == pstrName || strlen(pstrName) == 0) {
        return -1;
    }

    QString processName = QString::fromUtf8(pstrName);
    
    // 2. 启动进程
    QProcess process;
    // 使用 -o 参数只输出我们需要的信息,减少数据量:PID 和 CMD
    // 注意:不同系统 ps 参数可能略有不同,Linux 下通常如下
    process.start("ps", QStringList() << "-e" << "-o" << "pid,comm"); 
    
    if (!process.waitForFinished(5000)) {
        qWarning() << "ps command timeout or failed";
        process.kill();
        return -1;
    }

    QByteArray output = process.readAllStandardOutput();
    int count = 0;
    qint64 currentPid = QCoreApplication::applicationPid();
    bool ok = false;

    // 3. 解析输出
    // ps 输出第一行通常是标题 "PID CMD",需要跳过
    QList<QByteArray> lines = output.split('\n');
    for (int i = 1; i < lines.size(); ++i) {
        const QByteArray &line = lines[i].trimmed();
        if (line.isEmpty()) continue;

        // 解析 PID 和 CMD
        // 假设 ps 输出格式为 "PID  CMD",以空格分隔
        QList<QByteArray> parts = line.split(' ');
        if (parts.size() < 2) continue;

        qint64 pid = parts[0].toLongLong(&ok);
        QString cmd = QString::fromLocal8Bit(parts[1]); // comm 通常只显示进程名不含路径

        if (ok && pid != currentPid) {
            // 严格匹配进程名
            if (cmd == processName) {
                count++;
            }
        }
    }

    return count;
}

void Utils::killProcessByName(const char *pstrName)
{
    if (pstrName == NULL || strlen(pstrName) == 0) {
        return;
    }

    QProcess process;
    // killall 也是通过参数传递,安全
    process.start("killall", QStringList() << QString::fromUtf8(pstrName));
    
    // 等待结束,但不阻塞太久
    if (!process.waitForFinished(3000)) {
        qWarning() << "killall command timeout";
        process.kill();
    }
}

总结修改点:

  1. 逻辑修正:在 getProcessCountByName 中解析 ps 的结构化输出,而不是简单的字符串包含 (contains),避免了误匹配(如匹配到路径或参数)。
  2. 排除自身:获取 QCoreApplication::applicationPid() 并在统计时排除,防止逻辑错误。
  3. 性能优化:使用 ps -e -o pid,comm 仅获取 PID 和命令名,大幅减少数据传输量和内存占用。
  4. 安全保持:继续使用 QProcess 的参数列表模式,保持对命令注入的防御。

@LiHua000
Copy link
Author

/merge

@deepin-bot
Copy link
Contributor

deepin-bot bot commented Feb 11, 2026

This pr cannot be merged! (status: unstable)

@LiHua000
Copy link
Author

/merge

@deepin-bot deepin-bot bot merged commit 98ba4aa into linuxdeepin:release/eagle Feb 11, 2026
21 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.

4 participants