From 0721568d414f9464f46785e9cd5114f477438e4f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Mon, 14 Sep 2026 16:45:26 +0800 Subject: [PATCH] =?UTF-8?q?fix(codegen):=20=E6=B6=88=E9=99=A4=E6=B3=9B?= =?UTF-8?q?=E5=9E=8B=E7=89=B9=E5=8C=96=E9=9D=99=E9=BB=98=E5=85=9C=E5=BA=95?= =?UTF-8?q?=E5=B9=B6=E4=BF=AE=E6=AD=A3=20sha1=20=E5=89=8D=E7=BC=80?= =?UTF-8?q?=E5=BD=92=E4=B8=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 崩溃根因(已由 IR + 符号化确证):MatchGenMixin._handle_renum_match 的 body_list.get(bi) 被分派到 list[int].get,返回 i32 后 inttoptr 成 AST* 造成指针 32 位截断,运行期读 vtable 崩溃(ASan 坏地址 0xc1158310)。 第 1 步 方法分派:删除「ClassName 不含 [ 时按 Gen.structs 迭代顺序任选特化」的静默兜底,改为按接收者 LLVM 值类型的 pointee 用 find_struct_by_pointee 身份匹配反查唯一特化;反查不到时以「基名匹配且存在目标方法」求唯一候选,候选多于一个即 fail-fast,不再任选。 第 2 步 泛型实参:5 处「解析不出类型实参就补 int/CInt」改为 fail-fast。经核对语言与实现(wiki 类型系统/类章节、_generic_class_templates 的 type_params 无默认值机制、list 模板仅 1 参)确认泛型不存在合法缺省实参,5 处均属未知兜底。 第 3 步 注解赋值(真正的污染写入点):HandlesAnnAssign 中 bnm 与 CN 的比较未归一 sha1 模块前缀(注解侧裸名 list 与带前缀键 CN 恒不等),导致恢复特化名分支不命中、把裸泛型基名写入 var_struct_class,从而被第 1 步的兜底按顺序任选成 list[int]。改为与同函数既有 _cn_short 口径比较,构造仍用带前缀 CN。 --- lib/core/Handles/HandlesAnnAssign.py | 7 +- lib/core/Handles/HandlesExprCall.py | 95 +++++++++++++++++++--------- 2 files changed, 71 insertions(+), 31 deletions(-) diff --git a/lib/core/Handles/HandlesAnnAssign.py b/lib/core/Handles/HandlesAnnAssign.py index f243250..8040a2e 100644 --- a/lib/core/Handles/HandlesAnnAssign.py +++ b/lib/core/Handles/HandlesAnnAssign.py @@ -791,7 +791,12 @@ class AnnAssignHandle(BaseHandle): if isinstance(side, ast.Subscript): bn: ast.expr = side.value bnm: str | None = bn.id if isinstance(bn, ast.Name) else (bn.attr if isinstance(bn, ast.Attribute) else None) - if bnm and bnm == CN: + # 归一化比较:CN 可能带 16 位 sha1 模块前缀 + # (如 'e94ef9e139461915.list'),注解侧裸名为 + # 'list',直接与 CN 比较恒不等 ⇒ 特化名恢复失败 + # ⇒ 写入裸泛型基名 ⇒ .get() 按错误元素类型 + # 分派崩溃。用 _cn_short(已去前缀)比较。 + if bnm and bnm == _cn_short: sn2: ast.AST = side.slice if hasattr(ast, 'Index') and isinstance(sn2, ast.Index): sn2 = sn2.value diff --git a/lib/core/Handles/HandlesExprCall.py b/lib/core/Handles/HandlesExprCall.py index a14d70b..3bf7679 100644 --- a/lib/core/Handles/HandlesExprCall.py +++ b/lib/core/Handles/HandlesExprCall.py @@ -3131,23 +3131,43 @@ class ExprCallHandle(BaseHandle): _kind_ptr: ir.Value = Gen.builder.bitcast( ObjVal, ir.PointerType(ir.IntType(32)), name="renum_kind_ptr") return Gen._load(_kind_ptr, name="renum_kind") - # 泛型特化 fallback:当 ClassName 是 opaque 基础名(如 'ndarray',不含 '[') - # 且注解未指定类型参数时,遍历 Gen.structs 查找以 'ClassName[' 开头的特化版本 - # (如 'ndarray[double]'),优先选有对应方法的特化。这样方法调用能正确分派到 - # 特化版本的方法(如 ndarray[double].delete),而非查找 opaque stub declare。 + # 泛型特化定位:当 ClassName 是 opaque 基础名(如 'ndarray'/'list',不含 '[') + # 时,按【接收者 LLVM 值类型】反查唯一的具体特化,而不再遍历 Gen.structs 按 + # 迭代顺序任选一个 'ClassName[' 开头的特化——任选会命中 list[int] 之类元素 + # 类型错误的特化,方法返回 i32 被 inttoptr 当指针 → 运行期崩溃。 if '[' not in ClassName: SpecClass: str | None = None - for CN in Gen.structs.keys(): - if not CN.startswith(f'{ClassName}['): - continue - struct_sha1_tmp = getattr(Gen, '_struct_sha1_map', {}).get(CN) - if struct_sha1_tmp: - if Gen._has_function(f'{struct_sha1_tmp}.{CN}.{MethodName}'): - SpecClass = CN - break - if Gen._has_function(f'{CN}.{MethodName}'): - SpecClass = CN - break + # 1) 以接收者 LLVM 值类型的 pointee 结构体反查真实类名(唯一解)。 + _recv_found: tuple[str, ir.IdentifiedStructType] | None = None + _recv_type: Any = getattr(ObjVal, 'type', None) + if isinstance(_recv_type, ir.PointerType): + _recv_found = Gen.find_struct_by_pointee(_recv_type.pointee) + if _recv_found is not None and '[' in _recv_found[0]: + SpecClass = _recv_found[0] + # 2) 接收者实型无法唯一确定具体特化(裸泛型基类 / 反查不到结构体): + # 仅当「基名匹配 + 该类型下存在目标方法」的特化唯一时才采用;存在 + # 多个候选 ⇒ fail-fast(禁止按 Gen.structs 顺序任选)。0 个候选表示 + # 该基名下没有任何带此方法的特化(普通非泛型类方法调用路径),保持 + # ClassName 不变、交由后续常规分派。 + if SpecClass is None: + _base_src: str = _recv_found[0] if _recv_found is not None else ClassName + _base_short: str = Gen._extract_short_name(_base_src) + _cands: list[str] = [] + for CN in Gen.structs.keys(): + if '[' not in CN or CN.split('.')[-1].split('[')[0] != _base_short: + continue + struct_sha1_tmp = getattr(Gen, '_struct_sha1_map', {}).get(CN) + if struct_sha1_tmp and Gen._has_function(f'{struct_sha1_tmp}.{CN}.{MethodName}'): + _cands.append(CN) + elif Gen._has_function(f'{CN}.{MethodName}'): + _cands.append(CN) + if len(_cands) == 1: + SpecClass = _cands[0] + elif len(_cands) > 1: + raise Exception( + f"方法调用 '{MethodName}' 的接收者无法唯一确定泛型特化:" + f"基名 '{_base_short}' 下存在多个带该方法的结构体 {_cands}," + f"禁止按 Gen.structs 顺序任选(会分派到错误元素类型)。") if SpecClass: ClassName = SpecClass struct_sha1_map = getattr(Gen, '_struct_sha1_map', {}) @@ -3789,9 +3809,11 @@ class ExprCallHandle(BaseHandle): if result is not None: type_args.append(result[0]) type_names.append(result[1]) - while len(type_args) < len(type_param_names): - type_args.append('int') - type_names.append('CInt') + if len(type_args) < len(type_param_names): + raise Exception( + f"泛型类注解 '{ast.unparse(Sub)}' 无法解析全部类型实参:" + f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;" + f"禁止按 int 兜底。") # 类型注解解析(如 Float64Array: t.CTypedef = ndarray[t.CDouble]) # 只需 struct 定义,不需方法体;使用 declare_only=True 避免过早触发 # 完整特化(此时被引用的函数如 printf 可能尚未由 from X import Y 注册, @@ -4790,9 +4812,12 @@ class ExprCallHandle(BaseHandle): result = self._resolve_generic_slice_type(sn) if result is not None: type_args.append(result[0]) - # 补齐缺少的类型参数 - while len(type_args) < len(type_param_names): - type_args.append('int') + # 无法解析全部类型实参时禁止按 int 兜底(否则会特化出错误元素类型的函数) + if len(type_args) < len(type_param_names): + raise Exception( + f"泛型函数 '{FuncName}' 的显式类型实参无法全部解析:" + f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;" + f"禁止按 int 兜底。") type_args = type_args[:len(type_param_names)] # 特化 spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen) @@ -4836,9 +4861,15 @@ class ExprCallHandle(BaseHandle): type_str = self.Trans.FunctionHandler._infer_type_arg_from_value(arg_val, Gen) type_args.append(type_str) else: - type_args.append('int') - while len(type_args) < len(type_param_names): - type_args.append('int') + # 实参未产生 LLVM 值 ⇒ 无法推导其类型实参,禁止按 int 兜底 + raise Exception( + f"泛型函数 '{FuncName}' 调用无法从第 {i + 1} 个实参推导类型实参;" + f"禁止按 int 兜底。") + if len(type_args) < len(type_param_names): + raise Exception( + f"泛型函数 '{FuncName}' 调用无法推导全部类型实参:" + f"需要 {len(type_param_names)} 个,仅推导出 {len(type_args)} 个;" + f"禁止按 int 兜底。") type_args = type_args[:len(type_param_names)] spec_name = self.Trans.FunctionHandler._specialize_generic_function(FuncName, type_args, Gen) if spec_name is None: @@ -4880,10 +4911,12 @@ class ExprCallHandle(BaseHandle): if result is not None: type_args.append(result[0]) type_names.append(result[1]) - # 补齐缺少的类型参数 - while len(type_args) < len(type_param_names): - type_args.append('int') - type_names.append('CInt') + # 无法解析全部类型实参时禁止按 int 兜底(否则特化出错误元素类型的类) + if len(type_args) < len(type_param_names): + raise Exception( + f"泛型类 '{ClassName}' 的显式类型实参无法全部解析:" + f"需要 {len(type_param_names)} 个,仅解析出 {len(type_args)} 个;" + f"禁止按 int 兜底。") spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) if spec_name is None: return ir.Constant(ir.IntType(32), 0) @@ -4960,8 +4993,10 @@ class ExprCallHandle(BaseHandle): type_args.append(all_inferred[i][0]) type_names.append(all_inferred[i][1]) else: - type_args.append('int') - type_names.append('CInt') + # 第 i 个类型参数既无对应实参也无法推断 ⇒ 禁止按 int 兜底 + raise Exception( + f"泛型类 '{ClassName}' 构造调用无法为第 {i + 1} 个类型参数推导实参;" + f"禁止按 int 兜底。") spec_name = self.Trans.ClassHandler._specialize_generic_class(ClassName, type_args, Gen, type_names=type_names) if spec_name is None: return ir.Constant(ir.IntType(32), 0)