From cb557c84ce9e5dc23e25fa6106a46b029ba6d1c0 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 10 Aug 2026 18:09:05 +0800 Subject: [PATCH] =?UTF-8?q?fix(TPC):=20=5Fget=5Fmember=5Foffset=20?= =?UTF-8?q?=E7=9F=AD=E5=90=8D=E8=A7=84=E8=8C=83=E5=8C=96+=E8=B7=A8?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=E6=87=92=E5=8A=A0=E8=BD=BD+fast-fail?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit class_members/class_vtable/class_parent 以短名注册而调用方可能传 sha1 全名,且 class_members 未随 struct 就绪,导致查表全 miss 静默返回 None → 变量 alloca 未初始化 → 运行期读 0xffffffffffffffff 崩溃(HandlesImports.HandleImport imp.names)。修复:统一短名解析、主动懒加载 class_members、找不到字段改为 fast-fail raise 暴露 class_members/struct 真实状态。 --- lib/core/LLVMCG/FuncGen.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 2ba6123..bc9532f 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -237,6 +237,13 @@ class FuncGenMixin: # 此处检测冲突,加载正确模块的 class_members 并以 sha1 前缀全名缓存。 _ResolvedClass: str = ClassName if ClassName else '' if ClassName: + # 统一短名解析(治本修复 2026-08-10):struct/class_members/class_vtable/ + # class_parent 均以短名注册(跨模块加载 HandlesImports L1604),而调用方 + # 可能传入带 sha1 前缀的全名(如 "f47f88ae6545965a.Import"),导致下方 + # 查表全部 miss 返回 None → _gep_and_Load_member 静默返回 None → + # AnnAssign InitValue 为 None → 变量 alloca 未初始化 → 运行期读垃圾指针。 + ClassName = self._extract_short_name(ClassName) + _ResolvedClass = ClassName _ClassSha1Map: dict[str, str] = getattr(self, 'class_sha1_map', {}) _ExpectedSha1: str | None = _ClassSha1Map.get(ClassName) if _ExpectedSha1: @@ -289,6 +296,18 @@ class FuncGenMixin: isinstance(_first_elem.pointee, ir.IntType) and _first_elem.pointee.width == 8) if not _has_parent or _is_vtable_ptr: base = 1 + if ClassName and ClassName not in self.class_members and self._Trans and hasattr(self._Trans, 'ImportHandler'): + # 跨模块 class_members 懒加载:struct 已从 stub 加载但 class_members + # 可能尚未从 .vpi 填充(vpi/stub 就绪时序不一致),主动按类 sha1 加载。 + _Sha1sForLoad: dict[str, str] = getattr(self, 'class_sha1_map', {}) + for _mod_name_lz, _mod_sha1_lz in _Sha1sForLoad.items(): + try: + self._Trans.ImportHandler._TryLoadClassMembersFromPyi( + ClassName, f"{_mod_sha1_lz}.stub.ll", self) + except Exception: + continue + if ClassName in self.class_members and len(self.class_members[ClassName]) > 0: + break if _ResolvedClass and _ResolvedClass in self.class_members: for i, (name, _) in enumerate(self.class_members[_ResolvedClass]): if name == field_name: @@ -444,7 +463,22 @@ class FuncGenMixin: if _num_inherited_final == 1: # 单继承字段,偏移 = base(vtable 之后第一个位置) return base + 0 - return None + # fast-fail(治本修复 2026-08-10):字段未找到不再静默返回 None。 + # 静默 None 会让调用方(_gep_and_Load_member L26-27)直接 return None, + # AnnAssign InitValue 变 None → 变量 alloca 未初始化 → 运行期读垃圾指针 + # (如 HandlesImports.HandleImport 的 imp.names → 0xffffffffffffffff 崩溃)。 + # 抛出编译错误,暴露 class_members/struct 的真实状态便于定位根因。 + _members_diag: list = self.class_members.get(ClassName, []) if ClassName else [] + _struct_diag: str = 'not-registered' + if ClassName and ClassName in self.structs: + _st_diag = self.structs[ClassName] + if isinstance(_st_diag, ir.IdentifiedStructType): + _struct_diag = f"{len(_st_diag.elements)} elems" if _st_diag.elements is not None else 'opaque' + _member_names_diag: list = [n for n, _ in _members_diag][:16] + raise KeyError( + f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到" + f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})" + ) def _resolve_class_for_var(self, var_name: str) -> str | None: for ClassName in self.class_methods: