From 424dbd737966cd4be2df7a3b543252cb3d149a37 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Sun, 27 Sep 2026 12:52:03 +0800 Subject: [PATCH] =?UTF-8?q?chore(gen):=20=E5=8A=A0=20[MODSHA1]=20=E4=B8=B4?= =?UTF-8?q?=E6=97=B6=E8=AF=8A=E6=96=AD=E5=AE=9A=E4=BD=8D=20string.split=20?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E5=90=8D=E8=A7=A3=E6=9E=90=E5=A4=B1=E8=B4=A5?= =?UTF-8?q?=EF=BC=88=E5=AE=9A=E4=BD=8D=E5=90=8E=E5=88=A0=E9=99=A4=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 在 translate_call 的模块限定分支加两条探针: - [MODSHA1]:mod_ret_sha1 为 None 时打印 mod_path_ret / func_name / exact / suffix / ctrl_stdint(对照模块,必在 includes)——可区分 store 整体为空 与 store 有内容但缺该模块。 - [MODSHA1-D]:裸名兜底分支里,若 cl.func 仍是 Attribute(模块限定却解析不出模块的异常组合)则打印 mod_path_ret 与 func_name——覆盖 mod_path_ret 为 None 的情形。 同时把 mod_path_ret 的声明从 if 块内移到 if 外(与 mod_ret_sha1 一致),避免下游分支读未声明局部取到栈垃圾。 证据链:报错来自本函数 861 行(全仓唯一 fatal_if_unknown=1 的调用点),条件恒为 _resolve_module_sha1 对 string 返回 None;但 _sha1_map.txt 有 includes/string.vp、其 vpi 有 def split -> int、Phase1Main:390 是唯一写 map 处 ⇒ 静态无法解释,需运行时诊断。 --- App/lib/core/Gen/Call/CallGenMixin.vp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 570b096..e35fdaf 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -760,13 +760,15 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # _LookupMethodRetTyFromTextLL 的 strlen(0x1) 零页崩溃 # (llvmlite/__init__.vp CreateGlobalInt 翻译时 0xC0000005 根因)。 mod_ret_sha1: str = None + # [MODSHA1] 诊断用:模块名(cl.func 为 Attribute 时赋值,否则保持 None)。 + # 声明在 if 外,使下方裸名兜底分支也能安全读取(读未声明的局部 = 栈垃圾)。 + mod_path_ret: str = None if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: at_ret: ast.Attribute* = ast.Attribute*(cl.func) # 解析调用模块路径:单层(stdlib.free,value 是 Name)与多层 # (w32.win32file.CreatePipe,value 是嵌套 Attribute)都支持。 # 缺失多层路径 → mod_ret_sha1=None → 误走裸名外部函数路径, # fail-fast 误杀可收敛的模块限定调用(CreatePipe 根因)。 - mod_path_ret: str = None if at_ret.value is not None and at_ret.value.kind() == ast.ASTKind.Name: mod_ret_nm: ast.Name* = ast.Name*(at_ret.value) mod_path_ret = mod_ret_nm.id @@ -783,6 +785,20 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): if trans is not None: fi_from_rt = trans._from_imports mod_ret_sha1 = self.Gen.StructGen._resolve_module_sha1(mod_path_ret, fi_from_rt) + # [MODSHA1] 临时诊断(定位后删除):模块限定调用的模块名 → SHA1 + # 解析失败时,打印本模块名与对照模块名(stdint,必在 includes) + # 的精确/后缀查询结果,区分「store 整体为空」与「store 有内容但 + # 缺该模块」。devfs.vp 的 string.split 报错即经此分支。 + if mod_ret_sha1 is None: + dg_ex: str = self.Gen.CallGenBase._lookup_module_sha1(mod_path_ret) + dg_sf: str = self.Gen.CallGenBase._lookup_module_sha1_suffix(mod_path_ret) + dg_ctrl: str = self.Gen.CallGenBase._lookup_module_sha1("stdint") + if dg_ex is None: dg_ex = "-" + if dg_sf is None: dg_sf = "-" + if dg_ctrl is None: dg_ctrl = "-" + stdio.printf("[MODSHA1] mod='%s' fn='%s' exact=%s suffix=%s ctrl_stdint=%s line=%d\n", + mod_path_ret, func_name, dg_ex, dg_sf, dg_ctrl, cl.lineno) + stdio.fflush(None) if mod_ret_sha1 is not None: # 函数内懒 import:VpiReader imports HandlesExprCall, # 顶层 import 会成环(与 _lookup_method_ret_ty_via_vpi 一致) @@ -837,6 +853,14 @@ novirtual class CallGenMixin(CallGenBase.CallGenBase): # 本遍仅临时占位。 call_ret_ty = self.Gen.CallGenLib._infer_external_func_ret_ty(pool, func_name, node, 0) else: + # [MODSHA1] 临时诊断(定位后删除):走到裸名兜底 ⇒ mod_ret_sha1 为 + # None。仅当 cl.func 仍是模块限定形态(Attribute)时打印——这正是 + # "模块限定却解析不出模块"的异常组合(此时 mod_path_ret 为 None + # 说明 value 段不是 Name/Attribute;非 None 说明模块名查不到 SHA1)。 + if cl.func is not None and cl.func.kind() == ast.ASTKind.Attribute: + stdio.printf("[MODSHA1-D] mod='%s' fn='%s' line=%d\n", + mod_path_ret, func_name, cl.lineno) + stdio.fflush(None) # 裸名调用(cl.func 是 Name,mod_ret_sha1=None)两类来源:from-import 的函数(后续解析模块归属构造 mangled call_name 并经 text.ll/vpi 精确解析返回类型,可收敛)→ fatal_if_unknown=0 仅临时占位,不 fail-fast;纯外部 C 函数(无登记、无模块归属,白名单未命中)→ fail-fast(fatal_if_unknown=1)。闭包变量与持有函数指针/闭包的局部变量同样按可解析占位——返回类型由 translate_closure_call/lookup_var 路径固定处理,不依赖外部返回类型推断,否则被 fail-fast 误杀 bare_resolvable: int = 0 if self.Gen.CallGenLeafKit.is_closure_name(func_name) != 0: