diff --git a/lib/core/Handles/HandlesExprAttr.py b/lib/core/Handles/HandlesExprAttr.py index a0dc408..4caf966 100644 --- a/lib/core/Handles/HandlesExprAttr.py +++ b/lib/core/Handles/HandlesExprAttr.py @@ -21,6 +21,36 @@ class ExprAttrHandle(BaseHandle): val: ir.Value = Gen._load(ElemPtr, name="arr_elem_load") return Gen._apply_bswap_if_big(val, arr_byte_order, "bswap_arr_load") + @staticmethod + def _PointeeMatchesStruct(Pointee: Any, ST: Any) -> bool: + """pointee 与该 struct 实例是否算**同一个类**(判据分级,宽到窄)。 + + 原始判据只有"身份相同 / IR 全名逐字相同",遇到"同名类的另一份实例"就整条链放弃 + (现场:Repl.vp:802 `GenApi._g_gen.TypeGenCType.CTypedefNames` 的基座 pointee 是 + `%"750b8c10137d273e.TypeGenCType"*`,而 Gen.structs(250 键)里没有该 IR 名的实例 + ⇒ 身份与全名都不等 ⇒ 属性链求值为空终止编译)。故补两级退化判据: + + ① 同 IR 全名(原判据); + ② 同 sha1 前缀 —— IR 名形如 `.<短名>`,前缀相等即"同一模块的同一类" + (sha1 全名正是本仓为同名类冲突引入的命名形态)。 + + 同**短名**但不同 sha1 前缀的情形**不放行**(那可能是别模块的同名类,选错即静默 + 错布局):它由调用点在"同短名候选唯一"时单独放行(见 `_UniqShortCN`)。 + 找不到时仍返回 False(由调用点留痕,不兜底造类型)。 + """ + if Pointee is ST: + return True + if not (isinstance(Pointee, ir.IdentifiedStructType) + and isinstance(ST, ir.IdentifiedStructType)): + return False + _pn: str = getattr(Pointee, 'name', '') or '' + _sn: str = getattr(ST, 'name', '') or '' + if _pn and _pn == _sn: + return True + _pp: str = _pn.rsplit('.', 1)[0] if '.' in _pn else '' + _sp: str = _sn.rsplit('.', 1)[0] if '.' in _sn else '' + return bool(_pp and _sp and _pp == _sp) + def _gep_and_Load_member(self, Gen: LlvmCodeGenerator, ObjVal: ir.Value, offset: int | None, AttrName: str, ClassName: str, ST: ir.Type | None = None) -> ir.Value | None: """从结构体指针通过 GEP 取成员,处理 array/struct pointer/class_members 特殊情况""" if offset is None: @@ -967,8 +997,21 @@ class ExprAttrHandle(BaseHandle): parent_hint: str | None = self._resolve_attr_parent_hint(Node, Gen) if not parent_hint and isinstance(Node.value, ast.Attribute): parent_hint = self._resolve_chain_result_class(Node.value, Gen) or parent_hint + # 同短名候选:**唯一**时才放行(两个及以上同名类无法判定是哪一个, + # 宁可留痕失败也不能选错布局——同名类冲突在本仓一律以 sha1 全名区分)。 + _UniqShortCN: str | None = None + if isinstance(pointee, ir.IdentifiedStructType): + _PShort2: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1] + _ShortCNs: list[str] = [ + _c5 for _c5, _s5 in Gen.structs.items() + if isinstance(_s5, ir.IdentifiedStructType) + and (getattr(_s5, 'name', '') or '').rsplit('.', 1)[-1] == _PShort2 + ] + if len(_ShortCNs) == 1: + _UniqShortCN = _ShortCNs[0] for CN, ST in Gen.structs.items(): - if pointee == ST or (isinstance(pointee, ir.IdentifiedStructType) and isinstance(ST, ir.IdentifiedStructType) and pointee.name == ST.name): + if ((pointee == ST) or self._PointeeMatchesStruct(pointee, ST) + or (_UniqShortCN is not None and CN == _UniqShortCN)): st, ok = self._try_Load_struct_from_stub(Gen, CN) if not isinstance(st, ir.IdentifiedStructType) or st.elements is None: spec_val: Any = self._try_access_opaque_generic_member(Gen, ObjVal, st if isinstance(st, ir.IdentifiedStructType) else pointee, Node, CN, parent_hint) @@ -1018,9 +1061,21 @@ class ExprAttrHandle(BaseHandle): return self._gep_and_Load_member(Gen, ObjVal, offset, Node.attr, CN, st) # 结构体分支未命中任何类:pointee 与 Gen.structs 全部键都不等(同名类双实例 / # 该类未注册)——这是"基座类型已知却读不到字段"的最后一种来源,必须留痕。 + _PShortN: str = (getattr(pointee, 'name', '') or '').rsplit('.', 1)[-1] + _SameShort: list[str] = [] + for _cn3, _st3 in Gen.structs.items(): + if not isinstance(_st3, ir.IdentifiedStructType): + continue + if (getattr(_st3, 'name', '') or '').rsplit('.', 1)[-1] == _PShortN: + _SameShort.append(_cn3) self._NoteAttrNone( Gen, None, Node.attr, f"基座 pointee {pointee} 未匹配 Gen.structs 中任何 struct(键数={len(Gen.structs)})" + f";分级匹配(身份 / IR 全名 / 同 sha1 前缀)与「同短名 '{_PShortN}' 唯一候选」" + f"**全部未命中**,同短名候选={_SameShort if _SameShort else '无'}" + f"(候选 >1 时会被主动拒绝,避免选错同名类)" + f"——即该类在本 Gen 的 structs 里没有可用实例(另一 Gen/缓存的实例漏进来了," + f"或该类从未注册)" f";基座形态={self._ExprShape(Node.value)}") return None