基线重置,修复了一些 bug

This commit is contained in:
TermiNexus committed 2026-09-07 14:46:48 +08:00
1 parent 6b368b46a7
commit ed373a3ef2
8 files changed
+171 -17

No files matched your search

+10 -4
View File
@@ -494,10 +494,16 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
# 1a-pre-generic 只覆盖"可达"泛型文件;非可达泛型文件(如 FuncTest
# 场景的 linkedlist/llvmlite/_list)的模板要等 Phase2 Phase A-pre-inc
# (mark2 之后)才注册 → reset 回收表/节点 → _find_generic_template
# strcmp 悬空崩溃。此处对全部 includes 轻量预注册,使模板表与节点
# 都落在 mark1 之前(mark2 > mark1,reset_to(mark2) 不回收)。
# ============================================================
Phase1Scan._PreRegisterAllGenericTemplates(mb, result)
# 此处对全部 includes 轻量预注册,使模板表与节点都落在 mark1 之前。
# result 只是"可达子集",非可达的 _list/_dict/linkedlist/llvmlite 等泛型文件
# 模板不会注册 → list[int]/dict[...] 特化失败(ast/base.vp _dump_op_list 根因)。
# _PreRegisterAllGenericTemplates 内有 generic marker 文本预筛,全量扫描
# 不 parse 全部 AST,仅对含 marker 的文件轻量处理,OOM 风险可控。
full_scan_g: IncludesScanner.ScanResult | t.CPtr = IncludesScanner.scan_includes(mb, includes_dir)
if full_scan_g is not None:
Phase1Scan._PreRegisterAllGenericTemplates(mb, full_scan_g)
else:
Phase1Scan._PreRegisterAllGenericTemplates(mb, result)
# ============================================================
# Phase 1a: 注册 struct/enum/union(mark1 前,全量 includes)
+2
View File
@@ -341,6 +341,8 @@ def _PreRegisterAllGenericTemplates(mb: memhub.MemBuddy | t.CPtr,
stdlib.free(src_buf_pg)
if handled_count > 0:
VLogger.info(f"mark1 前永久池预注册 {handled_count} 个 includes 泛型类模板", "Phase1")
else:
VLogger.info(f"mark1 前永久池预注册 0 个泛型模板(扫描 {result.Count} 个文件,可能 marker 未命中或全量扫描失败)", "Phase1")
return handled_count
# ============================================================
# _FindClassDefSha1 - 在扁平数组中查找类名对应的定义文件 SHA1
+8 -4
View File
@@ -797,6 +797,8 @@ class CallGenCtor(CallGenBase.CallGenBase):
# 但步长按 4 计算,第 2 个元素覆盖第 1 个元素高 4 字节 → get 读出垃圾指针崩溃
result: list[str] | t.CPtr = list[str](pool, 8)
k: int = slice_node.kind()
tn_raw: str = None
tn: str = None
if k == ast.ASTKind.Tuple:
tp: ast.Tuple | t.CPtr = (ast.Tuple | t.CPtr)(slice_node)
elts: list[ast.AST | t.CPtr] | t.CPtr = tp.elts
@@ -805,15 +807,17 @@ class CallGenCtor(CallGenBase.CallGenBase):
i: t.CSizeT
for i in range(n):
elt: ast.AST | t.CPtr = elts.get(i)
tn_raw: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, elt)
tn: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
tn_raw = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, elt)
tn = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
if tn is not None:
result.append(tn)
else:
tn_raw: str = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, slice_node)
tn: str = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
tn_raw = self.Gen.TypeGenResolve._get_type_name_from_annotation(pool, slice_node)
tn = self.Gen.TypeGenResolve._norm_type_arg_name(pool, tn_raw, from_imports)
if tn is not None:
result.append(tn)
if len(result) == 0:
VLogger.info(f"[EXTRACT-DBG] 类型实参提取为空: kind={k} tn_raw={'Y' if tn_raw is not None else 'N'} tn={'Y' if tn is not None else 'N'}", "Phase1")
return result
# ============================================================
# 泛型类构造调用辅助: list[str](pool, 8) → __new__ + __before_init__ + __init__
+15
View File
@@ -600,7 +600,22 @@ class CallGenDispatch(CallGenBase.CallGenBase):
sz_resolved_name: str = sz_cls_name
if sz_cls_name is not None:
# 泛型类型参数 T 替换: T.__sizeof__() → int.__sizeof__()
sz_orig: str = sz_cls_name
sz_cls_name = self.Gen.TypeGenBase.resolve_generic_type_name(sz_cls_name)
# 兜底:TypeGenBase 上下文为空时(模板 tp_names 跨 phase 失效),
# 直接用 trans 的泛型映射替换 T(list[int] 单态化 _list.vp
# T.__sizeof__ 根因)。
if string.strcmp(sz_cls_name, sz_orig) == 0 and trans is not None \
and trans.GenericTypeParamNames is not None and trans.GenericTypeArgs is not None:
gp_n: t.CSizeT = len(trans.GenericTypeParamNames)
gp_i: t.CSizeT
for gp_i in range(gp_n):
gpn: str = trans.GenericTypeParamNames.get(gp_i)
if gpn is not None and string.strcmp(sz_orig, gpn) == 0:
gta: str = trans.GenericTypeArgs.get(gp_i)
if gta is not None:
sz_cls_name = gta
break
sz_resolved_name = sz_cls_name
# 保存完整名(含模块前缀)供模块归属精确匹配:去前缀后
# get_struct_type 裸名全局匹配会误命中跨模块同名类
+6 -1
View File
@@ -634,7 +634,12 @@ class StmtGenCifMixin:
and val_is_ptr == 0 and ret_is_ptr != 0:
val = llvmlite.build_inttoptr(builder, val, ret_ty_rt)
else:
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node)
# 传 trans:Phase A 依赖未就绪(_deps_pending)时,跨模块调用
# 返回类型退化为默认 i32,int→ptr 是退化指针重建而非隐式转换
# 错误,须跳过 fail-fast(与 AssignGenMixin/ExprGenBase 的
# _deps_pending 兜底一致)。否则 return 跨模块指针构造函数
# (如 SSAValue)误报"整数隐式转指针已禁止"。
val = self.Gen.ExprGenBase.coerce_to_type(builder, val, ret_ty_rt, node, trans)
elif val_is_ptr != 0 and ret_is_ptr != 0:
# 指针 → 指针且元素类型不同(如 t.CVoid(x, CPtr) 得到 i8*,
# 函数返回类型是类指针 Circle* 时)需 bitcast 回,
+25 -1
View File
@@ -718,6 +718,23 @@ class Translator:
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
if sub_s.value is not None:
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
elif k == ast.ASTKind.FunctionDef:
fd_s: ast.FunctionDef | t.CPtr = (ast.FunctionDef | t.CPtr)(node)
if fd_s.returns is not None:
self._check_container_type_node(fd_s.returns, need_list_box, need_dict_box)
if fd_s.args is not None:
args_s: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd_s.args)
if args_s.args is not None:
args_list_s: list[ast.AST | t.CPtr] | t.CPtr = args_s.args
an_s: t.CSizeT = len(args_list_s)
ai_s: t.CSizeT
for ai_s in range(an_s):
arg_s: ast.AST | t.CPtr = args_list_s.get(ai_s)
if arg_s is not None:
ag_s: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(arg_s)
if ag_s.annotation is not None:
self._check_container_type_node(
ag_s.annotation, need_list_box, need_dict_box)
# [FIX 2026-08-30] `[...]`/`{}` 字面量不再无条件触发 _list/_dict 导入:
# 字面量广泛用于编译期常量列表(c.Asm 的 op/inp/out CLOBBER 参数、
# 数组数据初始化),并非 list 容器使用。list/dict 容器的真实使用由
@@ -735,7 +752,7 @@ class Translator:
def _check_container_type_node(self, node: ast.AST | t.CPtr,
need_list_box: t.CPtr,
need_dict_box: t.CPtr):
"""检测类型位置节点是否为 list/dict(支持 Name 与 Subscript 外层)"""
"""检测类型位置节点是否为 list/dict(支持 Name / Subscript / BinOp 递归)"""
if node is None:
return
k: int = node.kind()
@@ -750,6 +767,13 @@ class Translator:
sub_s: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
if sub_s.value is not None:
self._check_container_type_node(sub_s.value, need_list_box, need_dict_box)
# rowptr[list[int]] / list[AST] 等:slice 里可能含 list,需下钻
if sub_s.slice is not None:
self._check_container_type_node(sub_s.slice, need_list_box, need_dict_box)
elif k == ast.ASTKind.BinOp:
bop_s: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(node)
self._check_container_type_node(ast.binop_get_left(bop_s), need_list_box, need_dict_box)
self._check_container_type_node(ast.binop_get_right(bop_s), need_list_box, need_dict_box)
def _annotation_is_container(self, ann: ast.AST | t.CPtr) -> int:
"""注解是否为 list/dict 容器(Name 裸名或 Subscript list[...]/dict[...])
+18 -4
View File
@@ -42,6 +42,20 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
# (rowptr[T] 固定 = 指向原始类型 T 的裸指针)。
if string.strcmp(name, "rowptr") == 0:
return
# 复制 name/type_str 到 pool:调用方可能传入零拷贝 AST 字符串
# (如 .vpi 读取缓冲区),缓冲区随后被 free 会导致表项悬空、
# lookup_ctypedef strcmp 失配、typedef 退化为 i8*(testcheck
# SetConsoleOutputCP 的 UINT 根因)。表须持有自己的字符串副本。
name_len: t.CSizeT = string.strlen(name)
name_copy: str = pool.alloc(name_len + 1)
if name_copy is None:
return
string.strcpy(name_copy, name)
type_len: t.CSizeT = string.strlen(type_str)
type_copy: str = pool.alloc(type_len + 1)
if type_copy is None:
return
string.strcpy(type_copy, type_str)
if self.CTypedefNames is None:
self.CTypedefNames = list[str](pool, 64)
self.CTypedefTypeStrs = list[str](pool, 64)
@@ -51,12 +65,12 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
ei: t.CSizeT
for ei in range(exist_n):
en: str = self.CTypedefNames.get(ei)
if en is not None and string.strcmp(en, name) == 0:
if en is not None and string.strcmp(en, name_copy) == 0:
# 已存在,更新类型字符串
self.CTypedefTypeStrs.set(ei, type_str)
self.CTypedefTypeStrs.set(ei, type_copy)
return
self.CTypedefNames.append(name) # 存疑
self.CTypedefTypeStrs.append(type_str)
self.CTypedefNames.append(name_copy)
self.CTypedefTypeStrs.append(type_copy)
def lookup_ctypedef(self, name: str) -> str:
"""查找 CTypedef,返回类型表达式字符串
+87 -3
View File
@@ -50,7 +50,10 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
# 导致 _specialize_generic_class("ndarray", ["T"]) 二次递归崩溃)
if k == ast.ASTKind.Name:
nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(node)
return self.Gen.TypeGenBase.resolve_generic_type_name(ast.name_get_id(nm))
# 直接用字段:ast.name_get_id 是跨模块访问器,Phase A 阶段 exprs.vp
# text.ll 未生成时该访问器是 stub(declare 无体)返回 None,导致
# 泛型类型实参提取失败(list[int] 的 int 被误判未提取)。
return self.Gen.TypeGenBase.resolve_generic_type_name(nm.id)
# Attribute: 构造 "module.attr" 格式
if k == ast.ASTKind.Attribute:
at: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(node)
@@ -648,6 +651,23 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
if btd_ty_r is not None:
return btd_ty_r
# 库 typedef 兜底:stdint 等库模块的裸 typedef(UINT/DWORD/...)定义在
# 依赖源中,_vpi_register_typedef_closure 因时序/上下文未成功注入当前
# 文件 CTypedef 表时,直接读库源注册并解析(testcheck.SetConsoleOutputCP
# 的 UINT 退化为 i8* 根因)。这是按权威源恢复正确类型,非静默降级。
lib_ts: str = self._lookup_library_typedef(pool, "stdint", name)
if lib_ts is None:
lib_ts = self._lookup_library_typedef(pool, "w32.win32base", name)
if lib_ts is not None:
lib_node: ast.AST | t.CPtr = self._parse_type_string(pool, lib_ts, ast.ASTCtx.Load)
if lib_node is not None:
if self.Gen.TypeGenCType.CTypedefResolveDepth < TypeGenMixin.MAX_CTYPEDEF_DEPTH:
self.Gen.TypeGenCType.CTypedefResolveDepth += 1
lib_ty: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
pool, lib_node, imported_modules, from_imports, trans, 1)
self.Gen.TypeGenCType.CTypedefResolveDepth -= 1
if lib_ty is not None:
return lib_ty
return self.map_t_type(pool, name)
def get_type_size_bytes(self, pool: memhub.MemBuddy | t.CPtr,
name: str,
@@ -721,7 +741,10 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
self.Gen.TypeGenCType.ImportAliasBuf = stdlib.malloc(256)
if self.Gen.TypeGenCType.ImportAliasBuf is None:
return
self.Gen.TypeGenCType.ImportAliasBuf[0] = '\0'
# 整体清零:别名段以空 alias('\0')终结,_resolve_import_alias 靠
# 末尾 '\0' 判定结束。只写 buf[0]='\0' 会导致追加后残留垃圾字节,
# 遍历读到未写入区域 → 越界读(ASan heap-buffer-overflow)。
string.memset(self.Gen.TypeGenCType.ImportAliasBuf, 0, 256)
buf: bytes = self.Gen.TypeGenCType.ImportAliasBuf
al_len: t.CSizeT = string.strlen(alias)
tg_len: t.CSizeT = string.strlen(target)
@@ -736,7 +759,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
while buf[cur] != '\0':
cur += 1
cur += 1 # 跳过 target 段的 '\0'
if cur + al_len + tg_len + 2 > 256:
# +3 = alias + '\0' + target + '\0' + 空 alias 终结 '\0'
if cur + al_len + tg_len + 3 > 256:
return
string.strcpy(buf + cur, alias)
cur += al_len
@@ -1499,6 +1523,17 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
sub: ast.Subscript | t.CPtr = (ast.Subscript | t.CPtr)(node)
if sub.value is None:
return None
# rowptr[T] 是内建裸指针(等价 t.CPtr[T]),AnnotClassName 应取 pointee
# 类名 T(字段访问按 T 查结构体),而非 "rowptr" / "rowptr[T]"——否则
# lookup_field_by_class 报"类 'rowptr' 未注册"(json.__parser _peek
# 参数 s: rowptr[ParseState] 根因)。
if sub.value.kind() == ast.ASTKind.Name:
rp_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(sub.value)
if rp_nm.id is not None and string.strcmp(rp_nm.id, "rowptr") == 0:
if sub.slice is not None:
return self.extract_class_name_from_annotation(
sub.slice, imported_modules, pool, from_imports)
return None
base_name: str = self.extract_class_name_from_annotation(sub.value, imported_modules, pool)
if base_name is None:
return None
@@ -1692,6 +1727,14 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
gen_spec_ty = self.Gen.StructGen.get_struct_type(gen_mangled)
if gen_spec_ty is not None:
return gen_spec_ty
else:
VLogger.info(f"[GENERIC-DBG] 特化失败(返回 None): {gen_cls_name}[{gen_mangled}]", "Phase1")
else:
VLogger.info(f"[GENERIC-DBG] 类型实参提取失败: {gen_cls_name}", "Phase1")
else:
VLogger.info(f"[GENERIC-DBG] 模板未注册: {gen_cls_name}", "Phase1")
else:
VLogger.info(f"[GENERIC-DBG] trans 为 None: {gen_cls_name}", "Phase1")
# 未特化:返回 None(不报错,让后续流程处理)
return None
def resolve_annotation_type(self, pool: memhub.MemBuddy | t.CPtr,
@@ -1901,6 +1944,20 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
pool, btd_node_n, imported_modules, from_imports, trans, depth + 1)
if btd_ty_n is not None:
return btd_ty_n
# 库 typedef 兜底:stdint / w32.win32base 等库模块的裸 typedef
# (BYTEPTR/DWORD/HANDLE/LPCSTR/...)定义在依赖源中,_vpi_register_typedef_closure
# 因时序/上下文未注入时,直接读库源注册并解析(string.vp BYTEPTR、
# win32process STARTUPINFOA 字段 HANDLE 根因)。与 resolve_typedef_or_map 同口径。
lib_ts_n: str = self._lookup_library_typedef(pool, "stdint", nm.id)
if lib_ts_n is None:
lib_ts_n = self._lookup_library_typedef(pool, "w32.win32base", nm.id)
if lib_ts_n is not None:
lib_node_n: ast.AST | t.CPtr = self._parse_type_string(pool, lib_ts_n, nm.ctx)
if lib_node_n is not None:
lib_ty_n: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
pool, lib_node_n, imported_modules, from_imports, trans, depth + 1)
if lib_ty_n is not None:
return lib_ty_n
return None
# Attribute 节点: t.CInt, t.CUInt64T, namespace_defs.PlainStruct 等
@@ -2073,6 +2130,21 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
mapped_ty_na: llvmlite.LLVMType | t.CPtr = self.map_t_type(pool, at.attr)
if mapped_ty_na is not None:
return mapped_ty_na
# 嵌套模块限定 typedef 兜底(w32.win32base.HANDLE = t.CTypedef =
# VOIDPTR):与单层 Module.Typedef 分支同口径,但 value 是嵌套
# Attribute,需先拼完整模块路径(w32.win32base)再读库源扫描注册。
# 缺失则 w32.win32base.HANDLE 字段解析失败 → File 整类 defer →
# 裸名 File(...) 构造检测 find_struct 落空 → 外部函数 fail-fast。
mod_path_na: str = self.Gen.ExprGenAttr._attr_module_path_str(pool, at.value)
if mod_path_na is not None:
lib_td_na: str = self._lookup_library_typedef(pool, mod_path_na, at.attr)
if lib_td_na is not None:
td_node_na: ast.AST | t.CPtr = self._parse_type_string(pool, lib_td_na, at.ctx)
if td_node_na is not None:
td_ty_na: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
pool, td_node_na, imported_modules, from_imports, trans, depth + 1)
if td_ty_na is not None:
return td_ty_na
return None
# BinOp 节点: 联合类型注解 A | B
@@ -2292,6 +2364,18 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
if self.Gen.TypeGenCType.ConstEvalOk == 0 or count_n <= 0:
return None
return llvmlite.Array(pool, elem_ty_n, count_n)
# rowptr[T] 内建裸指针:等价 t.CPtr[T] → Ptr(T)(T 自身可含指针层级)。
# 与 t.CPtr[T](下方 L2375 附近)语义一致;此前 rowptr[T] 走泛型特化
# / builtins 兜底失败 → "函数返回类型解析失败:注解不可解析"
# (ast.__init__.parse -> rowptr[AST] 根因)。
if string.strcmp(gen_nm.id, "rowptr") == 0:
if sub.slice.kind() != ast.ASTKind.Tuple:
rp_elem: llvmlite.LLVMType | t.CPtr = self.resolve_annotation_type(
pool, sub.slice, imported_modules, from_imports, trans, depth + 1)
if rp_elem is None:
return None
return llvmlite.Ptr(pool, rp_elem)
return None
gen_ty_nm: llvmlite.LLVMType | t.CPtr = self._resolve_generic_subscript_ty(
pool, sub, gen_nm.id, trans,
imported_modules, from_imports, depth + 1)