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:
TermiNexus committed 2026-08-20 10:28:29 +08:00
1 parent bd5d2467ab
commit f2cdbdc70f
3 files changed
+40 -13

No files matched your search

-4
View File
@@ -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
-6
View File
@@ -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:
+40 -3
View File
@@ -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