fix(codegen): 消除泛型特化静默兜底并修正 sha1 前缀归一
崩溃根因(已由 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。
This commit is contained in:
1 parent
d0f69eb90a
commit
0721568d41
2 files changed
+71
-31
No files matched your search
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in new issue
Block a user