Conversation
BUG-371743: 在 Loong64 V25 环境下登出时存在僵尸进程 bash,其父进程为
dde-session。
根因:sig_crash 信号处理函数标记 [[noreturn]],在调用 exit(-1) 前未回收
已退出的子进程。exit() 不会调用栈上局部对象(如 EXEC_COMMAND 宏创建的
QProcess)的析构函数,当信号在 waitForFinished(-1) 阻塞期间到达时,
QProcess 析构被跳过,子进程退出后成为僵尸进程残留。
修复(两层):
1. 根因层:在 sig_crash 的 doLogout() 之后、exit(-1) 之前,添加
while (waitpid(-1, nullptr, WNOHANG) > 0) {} 回收已退出的子进程。
waitpid 是异步信号安全函数,WNOHANG 保证不阻塞,覆盖所有信号中断场景。
2. 症状层:launchAutostopScripts() 中将 EXEC_COMMAND 宏替换为
QProcess::execute(),使用 Qt 标准 API,生命周期管理更规范。
PMS: https://pms.uniontech.com/bug-view-371743.html
|
[APPROVALNOTIFIER] This PR is NOT APPROVED This pull-request has been approved by: mhduiy 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 |
Reviewer's guide (collapsed on small PRs)Reviewer's GuideFixes zombie bash processes during crash-triggered logout by nonblocking-reaping exited children before exit, while replacing the autostop command macro with QProcess::execute for more reliable lifecycle management and error reporting. Sequence diagram for crash logout child reapingsequenceDiagram
participant Signal as sig_crash
participant Session as SessionManager
participant Child as ExitedChild
participant Kernel as Kernel
Signal->>Session: doLogout()
Session-->>Signal: return
loop exited children remain
Signal->>Kernel: waitpid(-1, nullptr, WNOHANG)
Kernel-->>Signal: child reaped
end
Signal->>Signal: exit(-1)
Note over Signal,Kernel: Running children are not blocked on and are reparented after exit
Sequence diagram for autostop script executionsequenceDiagram
participant Session as SessionManager
participant Process as QProcess
participant Script as AutostopScript
Session->>Process: execute(/bin/bash, arguments)
Process->>Script: run
Script-->>Process: exitCode
Process-->>Session: exitCode
alt exitCode != 0
Session->>Session: qWarning()
end
File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
deepin pr auto review🤖 AI 代码审查报告📊 总体评价
🔍 详细分析1. 语法逻辑 ✅评价: 优秀 ✅ 通过 潜在问题: 建议: ['#include <sys/wait.h> 正确引入,为 waitpid() 函数提供声明', 'QProcess::execute() 是 Qt 框架的合法静态方法,返回退出码', 'waitpid(-1, nullptr, WNOHANG) 参数使用正确:-1 等待任意子进程,nullptr 不保存退出状态,WNOHANG 非阻塞', 'while 循环条件 > 0 正确处理所有返回值:>0 表示成功回收子进程继续循环,0 表示无已退出子进程退出循环,-1 表示错误退出循环', 'exit(-1) 正确放置于 waitpid 回收之后,符合 [[noreturn]] 函数签名'] 2. 代码质量 ✅评价: 优秀 ✅ 通过 潜在问题: 建议: ['sig_crash 函数中的注释质量优秀:解释了 exit() 不调用析构函数的根本原因、EXEC_COMMAND 宏创建栈上 QProcess 的问题、waitpid 的异步信号安全性、WNOHANG 的非阻塞特性、仍在运行的子进程会被 reparent 到 init/systemd', '将 EXEC_COMMAND 宏替换为 QProcess::execute 静态方法,避免在调用者栈上创建 QProcess 对象,改善进程生命周期管理', "新增 qWarning() 日志输出比原宏的日志更具描述性('failed to run autostop script:' vs 'failed to run:')", '保留 qDebug() 输出脚本启动信息,便于调试', '无代码重复,无残留调试代码'] 3. 代码性能 ✅评价: 优秀 ✅ 通过 潜在问题: 建议: ['waitpid 使用 WNOHANG 标志确保非阻塞,不会在信号处理器中引入延迟', 'while 循环最多执行 N 次(N 为已退出子进程数),通常非常小,O(N) 复杂度合理', 'QProcess::execute() 与原 EXEC_COMMAND 宏性能等价,无性能回退', '正确回收僵尸进程,防止进程资源泄漏'] 4. 代码安全 🔒评价: 优秀 ✅ 通过
安全漏洞详情: 建议: ['waitpid 是 POSIX 标准定义的异步信号安全函数(signal-safety(7)),适合在信号处理器中使用', 'WNOHANG 标志确保信号处理器不会阻塞,避免死锁风险', 'waitpid 循环正确回收僵尸子进程,防止进程资源耗尽', 'QProcess::execute 的文件路径来自 QDir::entryInfoList 枚举特定目录,非用户可控输入,无命令注入风险', 'autostop 脚本执行是设计行为,目录权限(/etc/xdg/autostop 为 root 所有,用户配置目录为用户所有)保障安全性'] 💡 改进建议代码示例本报告由 AI 代码审查工具自动生成 |
修复 BUG-371743:登出时 dde-session 产生僵尸进程 bash
PMS: https://pms.uniontech.com/bug-view-371743.html
问题现象
在 Loong64 V25 环境下执行
ps aux | grep 'Z'检查时,发现存在僵尸进程bash([bash] <defunct>),其父进程为/usr/bin/dde-session。根因
sig_crash信号处理函数标记[[noreturn]],调用doLogout()后直接exit(-1)。exit()不会调用栈上局部对象的析构函数(C++ 标准[support.start.term])。当信号在
EXEC_COMMAND宏的waitForFinished(-1)阻塞期间到达时:
poll()被信号中断且不会重启(sig_crash为[[noreturn]]);QProcess p析构函数永远不会被调用,forkfd_wait()/forkfd_close()不会执行;waitpid回收而成为僵尸进程;doLogout()中的同步 DBus 调用会阻塞一段时间,此窗口内僵尸进程可被ps观测到。dde-session 也未设置 subreaper(
PR_SET_CHILD_SUBREAPER)或安装 SIGCHLD处理器,无任何兜底回收机制。
修复方案(两层)
根因层 —
sig_crash信号处理函数在
doLogout()之后、exit(-1)之前添加:waitpid是 POSIX 异步信号安全(async-signal-safe)函数,可在信号处理函数中安全调用;
WNOHANG保证不阻塞,仅回收已退出的子进程;仍在运行的子进程在dde-session 退出后会被 reparent 到 init/systemd 回收;
EXEC_COMMAND宏的场景,不仅限于launchAutostopScripts。症状层 —
launchAutostopScripts()将
EXEC_COMMAND宏替换为QProcess::execute(),使用 Qt 标准 API,生命周期管理更规范。
改动范围
仅
src/dde-session/impl/sessionmanager.cpp:#include <sys/wait.h>sig_crash:exit(-1)前增加waitpid回收循环launchAutostopScripts:EXEC_COMMAND→QProcess::execute验证
waitpid/WNOHANG/QProcess::execute三个 API 已通过独立编译、链接及运行测试验证(运行测试中
waitpid循环在exit(-1)前正常执行,退出码255 符合预期)。
libsystemd-dev/libglib2.0-dev等 -dev包及 DTK 代码生成工具而无法跑通,与本次改动无关。
影响
waitpid(-1, nullptr, WNOHANG)仅回收已退出子进程,不影响正在运行的子进程,回归风险低。
QProcess::execute()内部行为与原EXEC_COMMAND宏一致(创建 QProcesswaitForFinished(-1)),仅生命周期管理更规范,无行为变化。Summary by Sourcery
Reap exited child processes during crash handling and improve autostop script execution to prevent zombie bash processes during logout.
Bug Fixes:
Enhancements: