From f2cdbdc70fe3f3a0d6e8ba93033f267c2d851604 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 20 Aug 2026 10:28:29 +0800 Subject: [PATCH] =?UTF-8?q?fix(exprlen):=20=E5=89=A5=E7=A6=BB=20sha1=20?= =?UTF-8?q?=E5=89=8D=E7=BC=80=E4=BF=AE=E5=A4=8D=20len()=20=E5=88=86?= =?UTF-8?q?=E6=B4=BE=E5=A4=B1=E6=95=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit class_members/class_member_element_class 的 key 为裸类名,而 _CurrentCpythonObjectClass 可能带 sha1 前缀导致 gate miss 落到 strlen(stdint.vp 0xC0000005 根因)。同时按字段静态类型沿 MRO 分派 list.__len__,并移除排查期诊断 printf。 --- includes/ast/exprs.vp | 4 --- includes/llvmlite/__module.vp | 6 ---- lib/core/Handles/HandlesExprBuiltin.py | 43 ++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 13 deletions(-) diff --git a/includes/ast/exprs.vp b/includes/ast/exprs.vp index 85e54b9..574ef7f 100644 --- a/includes/ast/exprs.vp +++ b/includes/ast/exprs.vp @@ -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 diff --git a/includes/llvmlite/__module.vp b/includes/llvmlite/__module.vp index 39ed6e3..3d657fc 100644 --- a/includes/llvmlite/__module.vp +++ b/includes/llvmlite/__module.vp @@ -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: diff --git a/lib/core/Handles/HandlesExprBuiltin.py b/lib/core/Handles/HandlesExprBuiltin.py index e1b3050..e858efa 100644 --- a/lib/core/Handles/HandlesExprBuiltin.py +++ b/lib/core/Handles/HandlesExprBuiltin.py @@ -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