fix(exprlen): 剥离 sha1 前缀修复 len() 分派失效
class_members/class_member_element_class 的 key 为裸类名,而 _CurrentCpythonObjectClass 可能带 sha1 前缀导致 gate miss 落到 strlen(stdint.vp 0xC0000005 根因)。同时按字段静态类型沿 MRO 分派 list.__len__,并移除排查期诊断 printf。
This commit is contained in:
1 parent
bd5d2467ab
commit
f2cdbdc70f
3 files changed
+40
-13
No files matched your search
@@ -950,10 +950,6 @@ class Attribute(ExprNode):
|
||||
self.value = value
|
||||
self.attr = _copy_str(pool, attr)
|
||||
self.ctx = ctx
|
||||
# 诊断(stdint.vp Attribute.attr 垃圾定位):构造后打印 attr 副本地址
|
||||
stdio.printf("[DIAG] Attribute.__init__: this=%llu attr_src=%llu attr_copy=%llu value=%llu ctx=%d\n",
|
||||
t.CUInt64T(self), t.CUInt64T(attr), t.CUInt64T(self.attr),
|
||||
t.CUInt64T(self.value), self.ctx)
|
||||
|
||||
def kind(self) -> t.CInt:
|
||||
return ASTKind.Attribute
|
||||
|
||||
@@ -239,12 +239,6 @@ class LLVMModule:
|
||||
if func_scan.Params is not None:
|
||||
param_scan: Param | t.CPtr = func_scan.Params.Head
|
||||
param_scan_steps: t.CSizeT = 0
|
||||
if param_scan is not None:
|
||||
# 诊断(builtins.vp dump 卡死根因排查):对比访问器与
|
||||
# 直接字段访问的 param0/next——stub 字段访问若生成错误
|
||||
# GEP 会读到垃圾导致死循环。
|
||||
stdio.printf("[DIAG] param_scan 首节点: param=%llu next=%llu(函数名=%s)\n",
|
||||
t.CUInt64T(param_scan), t.CUInt64T(param_scan.Next), func_scan.Name)
|
||||
while param_scan is not None:
|
||||
param_scan_steps += 1
|
||||
if param_scan_steps > IR_DUMP_CHAIN_LIMIT:
|
||||
|
||||
@@ -553,15 +553,52 @@ class ExprBuiltinHandle(BaseHandle):
|
||||
attr_name = arg_node.attr
|
||||
len_member = f'{attr_name}__len'
|
||||
current_class = self.Trans._CurrentCpythonObjectClass
|
||||
if current_class and current_class in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[current_class]:
|
||||
# 关键:_CurrentCpythonObjectClass 可能带 sha1 前缀(如
|
||||
# 'a351387236c6ce1c.TypeGenCType'),而 class_members /
|
||||
# class_member_element_class 的 key 全部是裸类名。必须先把前缀剥离
|
||||
# 再做 `in Gen.class_members` 检查——否则带前缀时 gate 直接 miss,
|
||||
# 整个 self.attr 分支(含 list.__len__ 修复)被跳过,fall through
|
||||
# 到 strlen(stdint.vp 0xC0000005 崩溃根因)。
|
||||
bare_cls: str | None = current_class
|
||||
if bare_cls and len(bare_cls) > 17 and bare_cls[16] == '.':
|
||||
bare_cls = bare_cls[17:]
|
||||
if bare_cls and bare_cls in Gen.class_members:
|
||||
for m_name, m_type in Gen.class_members[bare_cls]:
|
||||
if m_name == len_member:
|
||||
self_val = Gen._get_var_ptr('self')
|
||||
if self_val:
|
||||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||||
offset = Gen._get_member_offset(len_member, current_class)
|
||||
offset = Gen._get_member_offset(len_member, bare_cls)
|
||||
len_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{len_member}_ptr")
|
||||
return Gen._load(len_ptr, name=f"self_{len_member}")
|
||||
# 修复 stdint.vp 崩溃(0xC0000005)根因:`list[X] | t.CPtr` 联合字段
|
||||
# 的 LLVM 类型退化为 i8*,_HandleLenLlvm 无法识别为 list,fall through
|
||||
# 到 strlen 分支 → 对 list 对象指针执行 strlen → 垃圾长度 → 越界 get
|
||||
# → 垃圾指针 → strcmp 崩。此处按字段静态类型(class_member_element_class
|
||||
# 记录的特化名,如 'list[str]',沿 MRO 链查找含父类)分派到 list.__len__。
|
||||
field_cls: str | None = None
|
||||
_elem_map: dict = getattr(Gen, 'class_member_element_class', {})
|
||||
for _mro_cls in Gen._get_mro_chain(bare_cls):
|
||||
# class_member_element_class 的 key 是裸类名(如 'TypeGenBase'),
|
||||
# _get_mro_chain 在输入裸名时也返回裸名链;再保险剥一次前缀。
|
||||
_mro_key: str = _mro_cls
|
||||
if len(_mro_cls) > 17 and _mro_cls[16] == '.':
|
||||
_mro_key = _mro_cls[17:]
|
||||
_sub: dict = _elem_map.get(_mro_key, {})
|
||||
if attr_name in _sub:
|
||||
field_cls = _sub[attr_name]
|
||||
break
|
||||
if field_cls and (field_cls == 'list' or field_cls.startswith('list[')):
|
||||
self_val = Gen._get_var_ptr('self')
|
||||
if self_val:
|
||||
self_ptr = Gen._load(self_val, name="self_for_len")
|
||||
offset = Gen._get_member_offset(attr_name, bare_cls)
|
||||
if offset is not None:
|
||||
list_ptr = Gen.builder.gep(self_ptr, [ir.Constant(ir.IntType(32), 0), ir.Constant(ir.IntType(32), offset)], name=f"self_{attr_name}_ptr")
|
||||
list_val = Gen._load(list_ptr, name=f"self_{attr_name}")
|
||||
result = self.Trans.ExprUtils._try_operator_overLoad(field_cls, '__len__', list_val, Gen)
|
||||
if result is not None:
|
||||
return result
|
||||
val = self.HandleExprLlvm(arg_node)
|
||||
if not val:
|
||||
return None
|
||||
|
||||
Reference in new issue
Block a user