curl 7.61.1 源码包构建异常:测试阶段失败的根因分析与排查实践

一、问题现象

在基于 curl-7.61.1-34.0.1 源码包进行 aarch64 架构的 RPM 构建时,构建过程在 %check 测试阶段异常终止。构建日志显示关键错误信息如下:

复制代码
BuildError: error building package (arch aarch64), mock exited with status 1
...
TESTDONE: 920 tests out of 977 reported OK: 94%
TESTFAIL: These test cases failed: 2 3 16 63 80 82 83 84 85 167 208 ...
...
RPM build errors:
error: Bad exit status from /var/tmp/rpm-tmp.K7Rmbt (%check)

从日志来看,测试套件共执行了 977 个测试用例,其中 920 个通过(通过率约 94%),57 个失败 ,最终导致 %check 阶段返回非零退出码,整个 RPM 构建被终止。

二、失败测试的分布特征

失败的测试用例编号分布广泛,包括 2、3、16、63、80、82、83、84、85、167、208、233、234、242、256、257、264、275、278、279、299、301、302、317、318、503、519、522、523、973、974、975、976、1075、1087、1088、1101、1134、1204、1212、1237、1248、1249、1250、1251、1259、1319、1321、1331、1401、1428、2023、2024、2025、2026、2029、2040。

从编号区间来看,失败用例覆盖了多种测试类型:

  • 低编号用例(2-300) :基础功能测试,如协议解析、URL 处理等
  • 中编号用例(500-1400) :HTTPS、FTP、代理等协议功能测试
  • 高编号用例(2000+) :扩展功能测试,如 Metalink、单元测试等

三、测试跳过情况分析

日志中还记录了 251 个被跳过的测试用例,跳过的原因具有重要的诊断价值:

跳过原因 次数 影响分析
"failed starting SSH server" 62 次 最主要的原因,涉及 SCP/SFTP/SOCKS 相关测试
"curl lacks debug support" 81 次 调试模式未开启,影响内存跟踪类测试
"curl lacks unittest support" 28 次 单元测试支持未编译
"curl lacks Metalink support" 16 次 Metalink 功能未启用
"disabled by keyword" 25 次 测试用例被主动禁用
"Test requires default test server host and port" 17 次 测试服务器配置不匹配

其中 SSH 服务器启动失败是最突出的问题,影响了 62 个测试用例的正常执行。这一问题的根因在 curl 官方文档中已有明确说明:

"Tests which use the ssh test server, SCP/SFTP/SOCKS tests, might get badly influenced by the output of system wide or user specific shell startup scripts, .bashrc, .profile, /etc/csh.cshrc, .login, /etc/bashrc, etc. which output text messages or escape sequences on user login."

也就是说,当 shell 启动脚本(如 .bashrc.profile 等)在登录时输出文本或转义序列时,这些输出会污染 SSH 测试服务器启动时的数据流 ,导致 sftp-server 或 ssh 客户端无法正常通信。典型错误表现为 SSH 服务器日志中出现 'Received message too long'

四、进程被强制终止(SIGKILL)现象

构建日志中出现了大量的进程被 SIGKILL 强制终止的记录:

复制代码
RUN: Process with pid 35883 forced to die with SIGKILL
RUN: Process with pid 37054 forced to die with SIGKILL
RUN: Process with pid 38677 forced to die with SIGKILL
...(共约 20 个进程被 SIGKILL)

SIGKILL 信号无法被进程捕获或忽略,通常由以下几种情况触发:

  1. 内存不足(OOM Killer) :构建环境内存资源不足时,内核会强制终止占用内存过大的进程。aarch64 架构的模拟构建环境(如 QEMU 用户态模拟)尤其容易出现此类问题。

  2. 超时机制:mock 构建系统或测试框架设置了超时阈值,当某个测试用例执行时间过长时会被强制终止。

  3. 测试服务器异常:如 SSH 服务器启动失败后,相关的测试进程可能陷入死循环或无限等待,最终被强制终止。

五、与已知问题的关联

在 CentOS 构建系统中,curl-7.61.1-28.el8 版本在 aarch64 架构上也曾报告过完全相同的构建失败:

复制代码
Result | BuildError: error building package (arch aarch64), 
mock exited with status 1; see root.log for more information

这表明该问题并非个例,而是 curl 7.61.1 在 aarch64 架构下具有较高的复现概率

此外,curl 7.61.1 版本在 Sparc/Solaris 平台上也曾报告过测试用例 1119 的失败,说明该版本的测试套件在不同架构和平台上均存在一定的兼容性问题。

六、解决方案建议

方案一:跳过测试阶段(临时方案)

对于急于完成构建的场景,可以在 RPM 构建时跳过 %check 阶段:

bash 复制代码
rpmbuild --define 'check exit 0' -ba curl.spec

⚠️ 注意 :此方案虽能完成构建,但跳过了所有测试验证,不推荐用于生产环境。

方案二:清理 Shell 启动脚本(针对性修复)

针对 SSH 服务器启动失败的问题,检查并清理构建用户(通常是 mockbuild)的 shell 启动脚本:

bash 复制代码
# 检查是否有输出语句
grep -r "echo\|printf" ~/.bashrc ~/.profile /etc/bashrc 2>/dev/null
# 临时禁用输出
alias echo=:  # 或在构建前注释掉输出行
方案三:禁用 SSH 相关测试

修改 tests/data/DISABLED 文件,将 SSH 相关的测试用例编号加入禁用列表,或通过 runtests.pl-k 参数跳过特定测试。

方案四:增加构建资源

如果问题源于 OOM Killer,可以:

  • 为 mock 构建分配更多内存
  • 在 aarch64 物理硬件上构建,避免 QEMU 模拟带来的性能开销
方案五:升级 curl 版本

curl 7.61.1 发布于 2018 年 9 月,已相对陈旧。后续版本对测试套件进行了大量改进和修复,升级到更新的 curl 版本是根本性的解决方案。

七、总结

curl 7.61.1 在 aarch64 架构下构建失败的直接原因是 %check 测试阶段存在大量测试失败(57 个失败用例)和测试跳过(251 个跳过用例),导致测试框架返回非零退出码。

深层原因主要包括:

  1. SSH 测试服务器启动失败(影响 62 个用例),根因是 shell 启动脚本的输出污染
  2. 进程被 SIGKILL 强制终止,可能与 OOM 或超时机制有关
  3. 该版本在 aarch64 架构下的已知兼容性问题

建议在实际项目中,优先考虑升级 curl 版本在测试前清理构建环境的 shell 启动脚本,以确保构建过程的稳定性和可靠性。