fix(tpc): 修复 t.CVoid 清理暴露的三处类型解析缺口
SymbolTypeResolver: 裸 t.CPtr 作 typedef 值(无联合、无下标)时按 void* 展开。_find_base_type 把 attr==CPtr 归一为小写 ptr,而守卫 _PTR_MODIFIERS 写的是 CPtr 命不中,导致 ptr 被当成类型名存进 OriginalType,最终建成 %"<模块sha>.ptr" 幻影结构体(HANDLE/VOIDPTR/DIR 报 cannot store i8* to ...ptr*)。改前 t.CVoid | t.CPtr 走 BinOp 分支恰好绕过 HandlesExprAttr: 属性访问的成员查找补继承链回退(对齐 HandlesExprUtils._get_var_class 的口径)。字段声明在基类时元素类表的键是声明类,而收件人是子类,原实现只查收件人类自身;方法调用侧早已做 MRO 查询,故 150 处 self.Gen.X.method() 未暴露。修后 self.Gen.TypeGenCType.ImportAliasBuf 可解析(该字段在基类 TypeGenBase),且此前被静默丢弃的 _register_import_alias malloc 分支恢复生效 TypeConvert._base_ctype_to_llvm: 注册表给出完整类型串(CPtr/CArrayPtr/CNeedPtr/CAutoPtr -> i8*)时不再返回 None(_llvm_str_to_ir 只认标量名),改走 _type_str_to_llvm——与同文件 _basic_type_to_llvm 既有口径一致;否则 PtrCount 循环会构造 ir.PointerType(None)(llvmlite opaque 指针,无 .pointee),在 HandlesFunctions._GetFunctionSignatureLlvm 抛 AttributeError(opendir 的 FATAL)。触发集合经全注册表扫描恰好 4 个类 等价性验证: 31614 个符号 + 37527 个真实注解点位逐条对比改前/改后差异 0 条(崩溃输入除外,由 opaque ptr 变为 typed i8**)
This commit is contained in:
1 parent
8d950f5d43
commit
033c0a7771
3 files changed
+110
-71
No files matched your search
@@ -465,8 +465,8 @@ class ExprAttrHandle(BaseHandle):
|
||||
|
||||
if not ClassName:
|
||||
# 单级 Name 字段取值的类名恢复(跨模块 stub 下 var_struct_class 缺失的
|
||||
# 兜底):本地变量(如 `tp: rowptr[Tuple] = (rowptr[Tuple])(node)`)可能
|
||||
# 因 rowptr[X] 被折叠为 i8* 而漏登记。若变量 alloca / 值本身可辨识为
|
||||
# 兜底):本地变量(如 `tp: rawptr[Tuple] = (rawptr[Tuple])(node)`)可能
|
||||
# 因 rawptr[X] 被折叠为 i8* 而漏登记。若变量 alloca / 值本身可辨识为
|
||||
# 结构体指针,按实际 pointee 恢复真实 Gen.structs 键并回填,避免属性
|
||||
# 访问求值 None 被 fail-fast 拦截(parser.vp `tp_elts = tp.elts` 根因)。
|
||||
if (VarName in Gen.variables or VarName in Gen._reg_values
|
||||
@@ -614,7 +614,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
else:
|
||||
Gen.var_struct_class[VarName] = ClassName
|
||||
# 通用指针槽兜底:静态类名(var_struct_class/键归一后)有效且 ObjVal 是指针,
|
||||
# 但 pointee 非 struct(如 cast 局部变量 tp: rowptr[Tuple] 的槽被建为 i32**,
|
||||
# 但 pointee 非 struct(如 cast 局部变量 tp: rawptr[Tuple] 的槽被建为 i32**,
|
||||
# Name 求值 load 一次得到 i32*,上述 struct 匹配/回退均不命中 → return None)。
|
||||
# 此时按静态类名信任 bitcast 到 struct* 再走成员 GEP(tp.elts 根因:
|
||||
# var_struct_class='Tuple'、structs 有 'Tuple',仅槽位为通用指针形态)。
|
||||
@@ -652,7 +652,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
Gen.class_member_bitoffsets[ClassName][AttrName] = bo
|
||||
return self._load_bitfield_member(ObjVal, ClassName, AttrName)
|
||||
|
||||
offset = Gen._get_member_offset(AttrName, ClassName)
|
||||
offset = Gen._get_member_offset(AttrName, ClassName)
|
||||
# 检查 offset 是否超出实际结构体
|
||||
if isinstance(ObjVal.type, ir.PointerType):
|
||||
actual_pointee: Any = ObjVal.type.pointee
|
||||
@@ -672,45 +672,45 @@ class ExprAttrHandle(BaseHandle):
|
||||
result = self._gep_and_Load_member(Gen, ObjVal, offset, AttrName, ClassName, st)
|
||||
return result
|
||||
|
||||
def _recover_struct_class(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
|
||||
"""由变量的 LLVM 存储类型恢复结构体类键(var_struct_class 缺失时兜底)。
|
||||
|
||||
单级 Name 字段取值(如 tp.elts)的本地变量,若其注解 rowptr[X] 被 TypeMerge
|
||||
builtins 分支折叠成 i8*、且 var_struct_class 未登记 X,属性访问层无法解析
|
||||
类名。此处直接检查 Gen.variables / _reg_values / _direct_values /
|
||||
global_vars 中该变量的 alloca(或值)指针 pointee:能辨识出
|
||||
IdentifiedStruct 就按 pointee 恢复真实 Gen.structs 键(精确匹配失败时按
|
||||
短名找元素最多的完整版本),供调用方回填并继续 GEP 成员访问。不发射任何
|
||||
额外 IR(纯查表)。
|
||||
"""
|
||||
if not VarName:
|
||||
return None
|
||||
probe: ir.Type | None = None
|
||||
vp: Any = Gen.variables.get(VarName)
|
||||
if vp is not None and isinstance(vp.type, ir.PointerType):
|
||||
probe = vp.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None:
|
||||
for reg in (Gen._reg_values.get(VarName), Gen._direct_values.get(VarName)):
|
||||
if reg is not None and isinstance(reg.type, ir.PointerType):
|
||||
probe = reg.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
break
|
||||
if probe is None and VarName in Gen.global_vars and hasattr(Gen, 'module') and VarName in Gen.module.globals:
|
||||
gv: Any = Gen.module.globals[VarName]
|
||||
if isinstance(gv, ir.GlobalVariable) and isinstance(gv.type, ir.PointerType):
|
||||
probe = gv.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None or not isinstance(probe, ir.IdentifiedStructType):
|
||||
return None
|
||||
found: Any = Gen.find_struct_by_pointee(probe)
|
||||
if found:
|
||||
return found[0]
|
||||
return self._pointee_llvm_to_struct_key(Gen, probe)
|
||||
|
||||
def _recover_struct_class(self, Gen: LlvmCodeGenerator, VarName: str) -> str | None:
|
||||
"""由变量的 LLVM 存储类型恢复结构体类键(var_struct_class 缺失时兜底)。
|
||||
|
||||
单级 Name 字段取值(如 tp.elts)的本地变量,若其注解 rawptr[X] 被 TypeMerge
|
||||
builtins 分支折叠成 i8*、且 var_struct_class 未登记 X,属性访问层无法解析
|
||||
类名。此处直接检查 Gen.variables / _reg_values / _direct_values /
|
||||
global_vars 中该变量的 alloca(或值)指针 pointee:能辨识出
|
||||
IdentifiedStruct 就按 pointee 恢复真实 Gen.structs 键(精确匹配失败时按
|
||||
短名找元素最多的完整版本),供调用方回填并继续 GEP 成员访问。不发射任何
|
||||
额外 IR(纯查表)。
|
||||
"""
|
||||
if not VarName:
|
||||
return None
|
||||
probe: ir.Type | None = None
|
||||
vp: Any = Gen.variables.get(VarName)
|
||||
if vp is not None and isinstance(vp.type, ir.PointerType):
|
||||
probe = vp.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None:
|
||||
for reg in (Gen._reg_values.get(VarName), Gen._direct_values.get(VarName)):
|
||||
if reg is not None and isinstance(reg.type, ir.PointerType):
|
||||
probe = reg.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
break
|
||||
if probe is None and VarName in Gen.global_vars and hasattr(Gen, 'module') and VarName in Gen.module.globals:
|
||||
gv: Any = Gen.module.globals[VarName]
|
||||
if isinstance(gv, ir.GlobalVariable) and isinstance(gv.type, ir.PointerType):
|
||||
probe = gv.type.pointee
|
||||
if isinstance(probe, ir.PointerType):
|
||||
probe = probe.pointee
|
||||
if probe is None or not isinstance(probe, ir.IdentifiedStructType):
|
||||
return None
|
||||
found: Any = Gen.find_struct_by_pointee(probe)
|
||||
if found:
|
||||
return found[0]
|
||||
return self._pointee_llvm_to_struct_key(Gen, probe)
|
||||
|
||||
def _handle_attr_nested(self, Node: ast.Attribute) -> ir.Value | None:
|
||||
"""处理 a.b.c 嵌套属性访问"""
|
||||
Gen: LlvmCodeGenerator = self.Trans.LlvmGen
|
||||
@@ -769,7 +769,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
# char* → struct* cast + 成员访问
|
||||
if isinstance(pointee, ir.IntType) and pointee.width == 8:
|
||||
# 两级自动解引用链(变量 = 指针.字段.成员,如 blk = func.Blocks.Head)
|
||||
# 根因修复:跨模块 stub 会把容器/类内指针字段(rowptr[GSList[BasicBlock]]
|
||||
# 根因修复:跨模块 stub 会把容器/类内指针字段(rawptr[GSList[BasicBlock]]
|
||||
# 等)退化为 i8*,此处 ObjVal 是刚从结构体字段 load 出的 i8*。必须恢复
|
||||
# 该字段声明的元素/特化类(如 'GSList[BasicBlock]')才能
|
||||
# bitcast + GEP + load 出成员。否则本函数返回 None → AnnAssign/Assign
|
||||
@@ -1718,7 +1718,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
_CurrentCpythonObjectClass 等)可能存在"裸名 vs 带 sha1 前缀"的不一致
|
||||
(如 key='Function',而持有者是 '732a8c24abb9b516.Function')。先精确
|
||||
匹配,再按短名(剥离 16 位 hex 前缀)遍历所有 key 匹配,确保能恢复
|
||||
字段声明的特化类(如 rowptr[GSList[BasicBlock]] → 'GSList[BasicBlock]')。
|
||||
字段声明的特化类(如 rawptr[GSList[BasicBlock]] → 'GSList[BasicBlock]')。
|
||||
"""
|
||||
if not OwnerClass or not FieldName:
|
||||
return None
|
||||
@@ -1733,6 +1733,24 @@ class ExprAttrHandle(BaseHandle):
|
||||
continue
|
||||
if FieldName in sub_map:
|
||||
return sub_map[FieldName]
|
||||
# 继承链回退(对齐 ExprUtils._get_var_class 的同一张表查询):字段声明在
|
||||
# 基类时 elem_map 的键是**声明类**,而收件人类可能是子类
|
||||
# (TypeGenBase.Gen: rawptr[Generator.Generator] → 收件人 TypeGenResolve /
|
||||
# TypeGenCType…)→ 上面两路全 miss。rawptr[X] 字段的 LLVM 成员类型被折叠
|
||||
# 为 i8*(struct 身份丢失,class_members / struct elements 都推不出目标类),
|
||||
# elem_map 是唯一能恢复目标类的来源;miss 即任意级链解析
|
||||
# (_field_element_key)返回 None → 带注解赋值 fail-fast
|
||||
# (TypeGenResolve.vp:807 self.Gen.TypeGenCType.ImportAliasBuf 根因)。
|
||||
try:
|
||||
_mro_chain: list[str] = Gen._get_mro_chain(OwnerClass)
|
||||
except Exception:
|
||||
_mro_chain = [OwnerClass]
|
||||
for _mro_cls in _mro_chain:
|
||||
_sub_mro: Any = elem_map.get(_mro_cls)
|
||||
if _sub_mro is None:
|
||||
_sub_mro = elem_map.get(Gen._extract_short_name(_mro_cls))
|
||||
if _sub_mro and FieldName in _sub_mro:
|
||||
return _sub_mro[FieldName]
|
||||
return None
|
||||
|
||||
def _resolve_attr_parent_hint(self, Node: ast.Attribute, Gen: LlvmCodeGenerator) -> str | None:
|
||||
@@ -1740,7 +1758,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
|
||||
例:func.Blocks.Head —— Node.value 是 func.Blocks,父变量 func 的
|
||||
var_struct_class/global_struct_class 是 'Function',Blocks 字段声明为
|
||||
rowptr[GSList[BasicBlock]],class_member_element_class 记录元素提示
|
||||
rawptr[GSList[BasicBlock]],class_member_element_class 记录元素提示
|
||||
'GSList[BasicBlock]'。该提示用于把退化为 i8* 的字段指针恢复成目标
|
||||
特化类(char* 分支),或在所有 GSList[T] 都有 Head/Tail/Count 时
|
||||
选择正确特化版本(struct 分支)。兼容裸名/带 sha1 前缀键。
|
||||
@@ -1888,7 +1906,7 @@ class ExprAttrHandle(BaseHandle):
|
||||
"""解析 OwnerClass 上 AttrName 字段的"元素 struct 键"(可在 Gen.structs 定位)。
|
||||
|
||||
供任意级链(ve.Alloca.Ty.Pointee)逐段恢复目标类:跨模块 stub 会把
|
||||
rowptr[X] 指针字段退化为 i8*,load 出的值丢失 struct 身份;此处综合
|
||||
rawptr[X] 指针字段退化为 i8*,load 出的值丢失 struct 身份;此处综合
|
||||
class_member_element_class(登记的元素/特化类)→ class_members LLVM
|
||||
成员类型 → struct elements 字段类型 推断该字段指向的 struct 键,
|
||||
兼容裸名/sha1 前缀/泛型特化名。
|
||||
|
||||
@@ -176,6 +176,14 @@ class TypeConvertMixin:
|
||||
return ir.VoidType()
|
||||
|
||||
llvm_str: str = CTypeRegistry.CTypeToLLVM(type(BaseType))
|
||||
# 注册表给出的是"完整类型串"(CPtr 家族 → 'i8*'):_llvm_str_to_ir 只认标量名
|
||||
# (void/i1..i128/float/double/half/fp128),'i8*' 取不到 ⇒ 返回 None ⇒ 调用方
|
||||
# _ctype_to_llvm 的 PtrCount 循环构造 ir.PointerType(None)(llvmlite opaque 指针,
|
||||
# 无 .pointee)⇒ HandlesFunctions._GetFunctionSignatureLlvm 访问 .pointee 抛
|
||||
# AttributeError。含 '*' 的串与 _basic_type_to_llvm 同口径,交给字符串→IR 解析
|
||||
# ('i8*' → IntType(8).as_pointer(),typed 指针)。
|
||||
if '*' in llvm_str:
|
||||
return self._type_str_to_llvm(llvm_str)
|
||||
return self._llvm_str_to_ir(llvm_str)
|
||||
|
||||
def _get_source_sha1_from_type_str(self, type_str: str) -> str | None:
|
||||
@@ -322,30 +330,30 @@ class TypeConvertMixin:
|
||||
while type_str.endswith('*'):
|
||||
ptr_depth += 1
|
||||
type_str = type_str[:-1].strip()
|
||||
if ptr_depth > 0:
|
||||
IsPtr = True
|
||||
# [builtins 最后匹配] typedef 下标字符串(rowptr[AST] / t.CPtr[AST]):
|
||||
# base 为 builtins 指针 typedef(rowptr → t.CPtr)时等价"指向切片类型",
|
||||
# 直接转 arg*,防止 stub/ToString 字符串化产物被误建为 'rowptr[AST]'
|
||||
# phantom 结构体(class_members 为空 → 属性访问 fail-fast KeyError)。
|
||||
_sub_m: re.Match | None = re.fullmatch(r'([A-Za-z_][A-Za-z0-9_.]*)\[([^\]]+)\]', type_str)
|
||||
if _sub_m:
|
||||
_sub_base: str = _sub_m.group(1)
|
||||
_sub_arg: str = _sub_m.group(2).strip()
|
||||
_is_ptr_td: bool = False
|
||||
try:
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR
|
||||
if _TAR.builtins_typedef_value(_sub_base):
|
||||
_is_ptr_td = True
|
||||
except Exception:
|
||||
_is_ptr_td = False
|
||||
if not _is_ptr_td and _sub_base in ('CPtr', 't.CPtr', 'c.CPtr'):
|
||||
_is_ptr_td = True
|
||||
if _is_ptr_td and _sub_arg:
|
||||
_sub_inner: ir.Type = self._type_str_to_llvm(_sub_arg, True)
|
||||
if IsPtr:
|
||||
return ir.PointerType(_sub_inner)
|
||||
return _sub_inner
|
||||
if ptr_depth > 0:
|
||||
IsPtr = True
|
||||
# [builtins 最后匹配] typedef 下标字符串(rawptr[AST] / t.CPtr[AST]):
|
||||
# base 为 builtins 指针 typedef(rawptr → t.CPtr)时等价"指向切片类型",
|
||||
# 直接转 arg*,防止 stub/ToString 字符串化产物被误建为 'rawptr[AST]'
|
||||
# phantom 结构体(class_members 为空 → 属性访问 fail-fast KeyError)。
|
||||
_sub_m: re.Match | None = re.fullmatch(r'([A-Za-z_][A-Za-z0-9_.]*)\[([^\]]+)\]', type_str)
|
||||
if _sub_m:
|
||||
_sub_base: str = _sub_m.group(1)
|
||||
_sub_arg: str = _sub_m.group(2).strip()
|
||||
_is_ptr_td: bool = False
|
||||
try:
|
||||
from lib.core.TypeAnnotationResolver import TypeAnnotationResolver as _TAR
|
||||
if _TAR.builtins_typedef_value(_sub_base):
|
||||
_is_ptr_td = True
|
||||
except Exception:
|
||||
_is_ptr_td = False
|
||||
if not _is_ptr_td and _sub_base in ('CPtr', 't.CPtr', 'c.CPtr'):
|
||||
_is_ptr_td = True
|
||||
if _is_ptr_td and _sub_arg:
|
||||
_sub_inner: ir.Type = self._type_str_to_llvm(_sub_arg, True)
|
||||
if IsPtr:
|
||||
return ir.PointerType(_sub_inner)
|
||||
return _sub_inner
|
||||
if type_str in {'typedef', 'CType', 'CVolatile', 'CEnum', 'CUnion', 'CStruct', 'enum', 'REnum', 'renum'}:
|
||||
result: ir.Type
|
||||
if IsPtr:
|
||||
|
||||
@@ -144,6 +144,19 @@ class TypeResolver:
|
||||
value_base_type: str | None = self._find_base_type(td.value)
|
||||
_PTR_MODIFIERS: frozenset[str] = frozenset({'CPtr', 'CArrayPtr', 'CConst', 'CVolatile', 'CInline', 'CStatic', 'CExtern'})
|
||||
|
||||
# 裸 t.CPtr(无 `|` 联合、无 `[T]` 下标):_find_base_type 把 node.attr == 'CPtr'
|
||||
# 归一化为指针标记 'ptr'(拼写与 _PTR_MODIFIERS 的 'CPtr' 不一致 ⇒ 下方守卫命不中),
|
||||
# 若让 'ptr' 落进 original_class,经 _InsertTypedefSymbol 存入 symtab.OriginalType 后
|
||||
# 会被 CTypeInfo.FromTypeName 当成 CStruct('ptr'),最终 _get_or_create_struct
|
||||
# 建出 %"<模块sha>.ptr" 不透明结构体(VLogger._console_handle: win32base.HANDLE
|
||||
# 报 "cannot store i8* to %"...ptr"*" 的根因)。按指针语义展开为 'void *',
|
||||
# 与改前 `t.CVoid | t.CPtr` 联合分支等价(_InsertTypedefSymbol 同样把
|
||||
# 'CVoid *' 归一化为 'void *')。
|
||||
if value_base_type == 'ptr':
|
||||
td.original_type_kind = 'typedef'
|
||||
td.original_class = 'void *'
|
||||
return
|
||||
|
||||
if value_base_type and value_base_type not in _PTR_MODIFIERS:
|
||||
cname: str | None = CTypeHelper.GetCName(value_base_type)
|
||||
if cname:
|
||||
|
||||
Reference in new issue
Block a user