diff --git a/lib/core/LLVMCG/FuncGen.py b/lib/core/LLVMCG/FuncGen.py index 1d6c502..3da0daa 100644 --- a/lib/core/LLVMCG/FuncGen.py +++ b/lib/core/LLVMCG/FuncGen.py @@ -975,12 +975,53 @@ class FuncGenMixin: 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] + # ---- 取证(只读,不改变行为,2026-09-30)---- + # 现场:CallGenDispatch.vp:787 `len_val.Ty.Pointee` 里 `.Pointee` 被判成在类 + # 'ParamNode'(2 字段 Next/Ty)里找 —— 而 'Pointee' 本属 LLVMType 的 REnum + # 变体镜像字段。要一次定位"是谁把接收者记成了 ParamNode",报文需给出: + # ① 本类键 → struct 实例 IR 名(键/实例名不一致即"同名两份实例"); + # ② **真正声明了该字段**的类键(唯一者即"本该用的类"); + # ③ var_struct_class 里被登记为**本类**的变量(封顶 6 个)及其实际 pointee + # IR 名 —— 两者不一致即"记录类名与实际 IR 类型不符",直接圈定记录点。 + _extra_diag: str = '' + try: + _st_key = self.structs.get(ClassName) if ClassName else None + if isinstance(_st_key, ir.IdentifiedStructType): + _extra_diag += (f"\n 本类键 '{ClassName}' → struct 实例 IR 名 " + f"'{getattr(_st_key, 'name', '?')}'") + _owners: list = [] + for _ck2, _cm2 in self.class_members.items(): + if _ck2 == ClassName: + continue + if any(_n2 == field_name for _n2, _ in (_cm2 or [])): + _owners.append(_ck2) + _extra_diag += (f"\n 声明了 '{field_name}' 的其它类键({len(_owners)} 个): " + f"{_owners[:8]}{' …' if len(_owners) > 8 else ''}") + _vsc: dict = getattr(self, 'var_struct_class', {}) or {} + _vars_here: list = [v for v, cn in _vsc.items() if cn == ClassName] + if _vars_here: + _vdesc: list = [] + for _v2 in _vars_here[:6]: + _pointee_desc: str = '?' + for _src3 in (getattr(self, 'variables', {}) or {}, + getattr(self, '_reg_values', {}) or {}, + getattr(self, '_direct_values', {}) or {}): + _val3 = _src3.get(_v2) + if _val3 is not None and isinstance(getattr(_val3, 'type', None), ir.PointerType): + _pointee_desc = str(_val3.type.pointee) + break + _vdesc.append(f"{_v2}(pointee={_pointee_desc})") + _extra_diag += (f"\n var_struct_class 登记为 '{ClassName}' 的变量(" + f"{len(_vars_here)} 个,示前 6): {_vdesc}") + except Exception as _e_diag: + _extra_diag += f"\n (取证附加信息生成失败: {type(_e_diag).__name__}: {_e_diag})" # 异常类型:MemberLookupFailFast(KeyError 子类 + 裸消息 __str__)—— # 既保留 `except KeyError` 兜底点,又让报文不再被 repr 成"带引号 + \n 转义" # 的不可读形式(原有 traceback.print_stack 调试转储一并移除,保持输出干净)。 raise MemberLookupFailFast( f"[fast-fail] 属性 '{field_name}' 在类 '{ClassName}' 中找不到" f"(class_members={len(_members_diag)} 个: {_member_names_diag}, struct={_struct_diag})" + f"{_extra_diag}" ) def _resolve_class_for_var(self, var_name: str) -> str | None: