5.1 KiB
GCC 偶发子进程启动失败:定位与恢复
日期:2026-09-13;分支:system-optimization。用户要求在元件语义修复过程中继续定位并处理偶发 GCC 错误。
已定位的事实
本机 GCC 8.1 本体能运行,但在启动 cc1.exe 的过程中偶发失败。详细 -v 记录已经打印了实际存在的绝对路径;添加编译器目录到 PATH 后,192 次串行/并发对照中的一组仍有一次失败,因此不能把 PATH 补全或并发关闭当成已证明的根因修复。
对本轮自行启动的 GCC 诊断进程设置临时 Windows 调试断点,捕获到一次同类失败:
CreateProcessA return = 0
GetLastError = 5 (ERROR_ACCESS_DENIED)
application = F:\Projects\mingw64\bin\..\libexec\gcc\x86_64-w64-mingw32\8.1.0\cc1.exe
gcc exit = 1
该样本是“拒绝访问”,不是“找不到 GCC 本体”。GCC 的 Windows 实现会把多种创建进程错误映射成 ENOENT,使终端只显示 CreateProcess: No such file or directory;这一信息损失也见 GCC 官方讨论。
只读核查发现:cc1.exe 存在,普通用户有读取/执行权限,没有 Zone.Identifier 下载标记,未查到相关 Defender/Code Integrity 拦截事件。诊断进程不在作业对象中。这些证据尚不能锁定 Windows 内部为何临时拒绝此次创建进程,也不能证明所有同类文本都对应错误 5。没有修改 ACL、安全配置、已安装 GCC 或系统 PATH。
同时捕获到独立异常:gcc --version 有时退出码为 0,但 stdout 为空;旧代码直接取首行,产生 IndexError,进一步把工具链问题变成了不明确的后端异常。
后台修复
- 保持
SIMULATION_NATIVE_CC/PATH 和SUNDIALS_ROOT的原查找规则,不写入任何本机绝对路径。Windows 将选中的编译器目录放入该子进程自己的 PATH;不修改后端全局环境。Linux 保留所配置命令及环境,包括依赖 argv[0] 的编译器包装器/符号链接。 - 正式构建与启动自检统一使用有效的空标准输入、受控的标准输出/错误管道、关闭无关句柄继承;Windows 隐藏编译器窗口。
- 正式构建只对已识别的 GCC 子进程启动错误、特定 Windows 临时进程错误,以及空编译器身份输出进行恢复。最多重试 5 次,间隔 0.05、0.1、0.2、0.35、0.5 秒。成功立即返回;失败日志保留,每次重试可追踪。
- C 语法错误、未定义符号等链接错误、缺失编译器和超时不走上述重试。版本/目标查询必须有有效输出,空版本不会再触发 IndexError。
- 启动自检的整轮重试仍由既有后台状态机管理:首次检测加最多 5 轮,编辑器可用,最终失败才展示详细错误。自检预处理/编译/链接命令不再额外叠加一层整轮重试;编译器身份查询可使用命令级恢复。
- 正式构建记录
compilerLaunchRetries(构建命令的次数,独立的版本查询恢复在服务器日志中记录);最终编译失败保留命令、退出码、stdout/stderr、尝试次数等详情。启动自检明确描述为“GCC 已启动,但无法启动编译子进程”,避免再让用户误以为只需重配 gcc 路径。
这修复了应用把一次可恢复启动失败直接判为仿真失败的行为;没有声称消除了 Windows 层所有拒绝访问的根源。若六次启动仍失败,仍会如实报错,不更换编译器、不绕过系统安全限制。
验证
- 修复后 128 次、并发度 4 的真实预处理调用全部完成。期间再次捕捉到 1 次相同 CreateProcess 失败,自动重试一次成功,无需手动重启后端。
- 连续 10 次完整启动自检全部通过,每次均执行预处理、编译、SUNDIALS 链接和最小 BDF 程序运行,未使用模型缓存。
- 进程专项测试覆盖瞬时错误恢复、重试上限、日志保留、真实语法/链接错误不重试、空版本、超时/缺失文件、环境隔离、Linux 分支,以及最终身份查询失败的完整自检详情;最后检查见
final-process-detail-tests.log。 - 元件与启动自检综合 43 项回归通过;最终编译进程/启动自检/历史合同组合 25 项通过;最终元件/目录检查 14 项通过。后续四路真实构建过程中再出现两次启动抖动,也都自动恢复并完成仿真。独立数值探针曾有一次空输出导致测试失败,保留记录并完整重跑通过;没有据此扩大为任意仿真进程的自动重跑。
- Linux 适配由跨平台分支测试覆盖;本次未登录 Linux 服务器做实机验证。
证据目录:test/component-semantics-20260913/。原始对照为 gcc-probe.json;原始 Windows 错误码为 gcc-debug4.log;恢复压力测试为 launch-verification.json;专项为 compiler-process-tests.log、final-launch-and-contract-tests.log。调试程序仅留在被忽略的 test 目录,不加入生产程序,也未修改磁盘上的编译器。
修改后需要后端进程加载新代码。已有运行进程不会因磁盘文件变更自动得到新逻辑(除非本身启用了 reload)。