7.7 KiB
Debug: StmtGenMixin 拆分后 FuncTest 运行时崩溃
Session ID: stmtgen-split-crash Status: [OPEN] Created: 2026-08-17
症状
- 拆分 StmtGenMixin.vp → 3 文件(顶层 763 / StmtGenDeclMixin 512 / StmtGenCifMixin 520)后
- PhaseC SUCCESS(FuncTest.exe 编译链接成功)
- 运行时输出:
=== FuncTest: 函数调用基准测试 === --- Test 1: basic function call --- PASS: add(10,20)=30 FAIL: add(10,20) expect 30 然后崩溃
回归窗口
- 拆分前(git restore 的原始 StmtGenMixin.vp 1715 行)FuncTest 应正常
- 拆分改动:类结构 StmtGenMixin → StmtGenDeclMixin → StmtGenCifMixin 三级继承;字段全留最底层 Cif;方法按功能域分 3 文件
根因(已确认,证据充分)
崩溃根因:FuncGenMixin/ClassGenMixin 对"末句控制流"无条件生成 unreachable(追加89),而 llc O2 将 br label %merge(merge: unreachable)优化为 fall-through → 双分支执行。
- 证据链:
- FuncTest check 机器码:
testl %ecx; je fail; callq ok; (fall-through) callq fail—— ok 后无跳转直接执行 fail → PASS+FAIL 双打印 +int3崩溃 - check IR:
br label %if.end.4+if.end.4: unreachable(merge 可达却被判 unreachable) - [HandlesIf.vp L302-315]:分支未 return 时 br 到 merge(merge 可达);全 return 时不 br(不可达)
- FuncGenMixin/ClassGenMixin 判定
last_is_ctrl → build_unreachable不区分 merge 可达性 → bug
- FuncTest check 机器码:
- 与 StmtGenMixin 拆分逻辑无关(HandlesIf/FuncGenMixin/ClassGenMixin 均未拆分);拆分暴露了该 bug(FuncTest check 是"末句 if + 无注解 + merge 可达"函数)
修复(追加90,7 文件)
HandlesTranslator.vp:Translator 加字段_ctrl_merge_reachable(控制流 merge 可达性)HandlesIf.vp:结尾按 then/else 分支 br 情况设置(无 else 恒 1;有 else 任一 br → 1;全 return → 0)HandlesWhile.vp:cond_br 恒引用 end_bb → 设 1HandlesFor.vp:7 个迭代器 end_bb 处设 1HandlesMatch.vp:Handle 开头重置 0;br end_bb 处设 1FuncGenMixin.vpL1140:last_is_ctrl且_ctrl_merge_reachable == 0才 unreachable;可达 → 正常收尾(ConstZero/fail-fast)ClassGenMixin.vpL4536:方法收尾路径同步
验证要点:check(merge 可达)→ ConstZero ret;get_struct_name(全 case return)→ unreachable 保持
修正(追加90 v2:避免循环依赖)
- 初版缺陷:把
_ctrl_merge_reachable放 Translator 实例字段 → HandlesMatch/If/While/For 方法体引用trans._ctrl_merge_reachable需 Translator 字段表,而 HandlesTranslator 依赖 HandlesMatch.NewMatchHandle → HandlesMatch ↔ HandlesTranslator 循环依赖 → TPC 声明顺序死锁 → MatchHandle struct opaque、方法/工厂符号全缺失 → 连锁报错(1.LOG 证据) - 修正 v2:改放 HandlesBase 模块级全局 +
SetCtrlMergeReachable(val)/GetCtrlMergeReachable()(无 struct 依赖,无循环;跨模块函数调用仅依赖 Phase1 stub)- HandlesTranslator.vp:字段回滚(已删)
- HandlesBase.vp:加
_ctrl_merge_reachable+ Set/Get 函数 - HandlesIf/While/For/Match:调用
HandlesBase.SetCtrlMergeReachable(1/0) - FuncGenMixin/ClassGenMixin:
HandlesBase.GetCtrlMergeReachable() == 0+ import HandlesBase
- 已知残余风险:模块级全局在多线程并行编译(Phase2Translator._parallel_translate_worker)下有竞争(_g_cif_eval_ok 先例同样存在且工作正常,暂接受)
真正的根因(1.LOG 定位,v3 修正)
- 1.LOG L3:
HandlesMatch.vp: invalid syntax (line 976)——批量脚本_patch_ctrl.py的 replace 把HandlesBase.SetCtrlMergeReachable(1)误插到if nb_arr[ci]==0: br end_bb与else:之间 → else 悬空语法错误 - 语法错误使 TPC 无法解析 HandlesMatch.vp → MatchHandle struct opaque、Handle 方法无声明、NewMatchHandle 符号 undefined → 依赖它的 StmtGenCifMixin(NewMatchHandle 内 h.Trans = trans)/HandlesTranslator 连锁报错
- v1(Translator 字段)/v2(HandlesBase 全局)都报同一 MatchHandle 错误的原因:真正的障碍一直是语法错误,不是依赖方案
- 修正 v3:删除 HandlesMatch.vp L975 误插行,if-else 结构恢复;其余 8 处 SetCtrlMergeReachable 位置已验证合法
最终方案(v1 定稿,重建成功)
-
v1/v2 的 MatchHandle 错误其实是 L975 语法错误(误判为循环依赖)
-
v3(HandlesBase 模块级全局)编译通过但 TPV 编译器运行时崩(win32base Struct 收到全垃圾参数 → pool 悬空,插桩 DBG-ST 证实)
-
定稿 v1:
trans._ctrl_merge_reachable字段(线程安全,per-trans 无全局共享)+ 控制流翻译器写 + FuncGen/ClassGen 判定读 -
2026-08-17 用户验证:清缓存重建成功 ✓
-
待验证:FuncTest 运行(check 不再 PASS+FAIL 双打印)、68 测试回归
-
H1 跨模块继承字段布局错位:Generator 组合布局中 StmtGenMixin 链字段块位置与各 Mixin 独立布局不一致 → self 字段访问偏移错误 → 函数表/状态错乱
-
H2 跨模块继承 struct 加载失败:TPV 编译 Generator.vp 时从 vpi/stub 加载 StmtGenCifMixin 字段定义失败(opaque)→ 组合布局损坏
-
H3 self.method 沿 MRO 的 this 调整错误:translate_stmt 调 Decl/Cif 方法时 this_adjust 偏移算错 → 方法内字段访问错乱
-
H4 模块级符号跨文件解析:顶层/Decl 方法引用的模块级常量(ENUM_MAX 等)或符号解析失败降级 → 编译期静默错误
-
H5 编译链未清缓存:tpv.exe 为旧产物(未含拆分逻辑)或新文件依赖顺序错误 → 生成代码错误
证据计划
- 确认用户验证方式(是否 --clean --rebuild-includes --clear-cache + Phase A 全量重建)
- 确认拆分前 FuncTest 是否正常(回归基线)
- 插桩定位崩溃点与字段偏移(TPV 侧或 FuncTest 侧)
状态日志
2026-08-17 证据收集 2(TPV 自身产物 + asan 发现)
- TPV 自身编译产物(output/0d5dfc518e9dbf1c.ll 4:54:31):
- 三 class struct 布局完全一致:
{ i64, EnumEntry*, i32, i32 }✓ - translate_stmt 跨 Mixin 调用正确:
bitcast StmtGenMixin* → StmtGenDeclMixin*+ 调用9df7bd403cb4eb0a.StmtGenDeclMixin.translate_expr_stmt(L4195-4196)✓ - TPV 编译器自身(拆分后)编译正确
- 三 class struct 布局完全一致:
- 新证据:FuncTest.exe 是 ASan 插桩版!
- output/06/067f811511854c88.asan.ll 存在(4:54:45),内容是 LLVM bitcode(BC 头,非文本 IR)
- FuncTest.exe 含
__asan_init/__asan_report符号 - project.json linker flags 无 asan 运行时库(只有 msvcrt/ucrt/pthread/mingwex/kernel32/user32)
- 新假设 H6:崩溃是 --asan 编译模式导致(main 插桩 + asan 运行时未正确初始化/链接),与 StmtGenMixin 拆分无关。拆分前 68 测试全过可能不带 --asan
- 待确认:用户编译 FuncTest 的命令是否带 --asan;拆分前测试是否带 --asan
- 分析 Test/FuncTest/.tpv_build/temp 的 .ll(4:46 产物):
067f811511854c88.llL535:call i32 @add(i32 10, i32 20)✓ 参数正确748d0424e8976fa0.llL271-293(check):br i1 %4, if.then.4/if.else.4✓ 条件跳转正确;ok/fail 各打印一次 ✓- ok/fail 函数 L245-269:单次 printf ✓
- 结论:FuncTest 生成代码完全正常。PASS+FAIL 双打印+崩溃非生成代码所致
- 倾向 H5:编译链产物混用(tpv.exe 未含拆分逻辑的旧产物/缓存复用);用户正在重编译
- 下一步:用户完成"清缓存 + Phase A 全量重建"后重跑 FuncTest 验证