diff --git a/App/lib/Phase/Phase1/Phase1Main.vp b/App/lib/Phase/Phase1/Phase1Main.vp index 327fd2d..6f57947 100644 --- a/App/lib/Phase/Phase1/Phase1Main.vp +++ b/App/lib/Phase/Phase1/Phase1Main.vp @@ -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) diff --git a/App/lib/Phase/Phase1/Phase1Scan.vp b/App/lib/Phase/Phase1/Phase1Scan.vp index 3fc360a..0df2a25 100644 --- a/App/lib/Phase/Phase1/Phase1Scan.vp +++ b/App/lib/Phase/Phase1/Phase1Scan.vp @@ -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 diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 0a8d50c..8ddd5b9 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -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__ diff --git a/App/lib/core/Gen/Call/CallGenDispatch.vp b/App/lib/core/Gen/Call/CallGenDispatch.vp index 431a985..cbaf9c2 100644 --- a/App/lib/core/Gen/Call/CallGenDispatch.vp +++ b/App/lib/core/Gen/Call/CallGenDispatch.vp @@ -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 裸名全局匹配会误命中跨模块同名类 diff --git a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp index ca86f8f..aa0a41f 100644 --- a/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp +++ b/App/lib/core/Gen/Stmt/StmtGenCifMixin.vp @@ -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 回, diff --git a/App/lib/core/Gen/Translator.vp b/App/lib/core/Gen/Translator.vp index c93b6bc..0582aeb 100644 --- a/App/lib/core/Gen/Translator.vp +++ b/App/lib/core/Gen/Translator.vp @@ -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[...]) diff --git a/App/lib/core/Gen/Type/TypeGenCType.vp b/App/lib/core/Gen/Type/TypeGenCType.vp index 7807106..52fc91e 100644 --- a/App/lib/core/Gen/Type/TypeGenCType.vp +++ b/App/lib/core/Gen/Type/TypeGenCType.vp @@ -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,返回类型表达式字符串 diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index 385c32d..c6b5c5b 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -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)