fix(tpv): 修模块级浮点全局零初始化、跨模块 CDefine 重导出、默认参数快照、typedef 诊断悬垂指针
- TranslatorGenMixin/AssignGenMixin: 模块级全局补 CONST_FLOAT 初始化分支。 此前无此分支 → init_kind 保持 0 → t.CDouble 全局一律退化成 zeroinitializer (torch 的 LCG_A/LCG_M/_rng_state 全变 0 → _next_rand() 得 0.0/0.0 = NaN → Kaiming 初始化写入全 NaN 权重 → 推理 softmax 分母 NaN → 十个概率全为 0)。 浮点值不走 AST 的 float_val(会被 pool 操作覆写),改为按变量名从当前源文件 重读恢复;_recover_cdefine_float 泛化为 _recover_float_literal。 - ExprGenCdef: 跨模块 CDefine 重导出链支持绝对导入(from pkg.sub import *), 此前只认相对 from .X → vqt6 包(__init__.vp 用 from vqt6._types import *) 里的 CDefine 全查不到,报 "跨模块 CDefine 未找到: 'vqt6.QT_ALIGN_CENTER'"; 相对导入基准改用"当前模块所属包"而非模块名本身,修正子模块 from .X 拼接 (对齐 CallGenBase._lookup_reexport_from_vpi 的包名口径)。 - CallGenLeafKit: 默认参数常量快照支持一元字面量(USub/UAdd/Invert 且操作数为 整型 Constant)。此前只认 Constant/Name → ex3: t.CInt = -1 这类默认值快照为空, 跨模块重建时报 "跨模块默认参数无法重建(快照缺失)"。其余形态仍保持 kinds=0, 重建时 fail-fast,不静默兜底。 - TypeGenCType/TypeGenResolve/TypeGenBase: builtins typedef 诊断串改为自有缓冲 副本(stdlib.malloc,clear_ctypedefs 释放)。调用方常传临时段缓冲,直接存指针 会悬垂,_build_ann_fail_msg 的 snprintf 读已释放内存(ASan heap-use-after-free)。
This commit is contained in:
1 parent
adfd202218
commit
76f03b5987
7 files changed
+206
-35
No files matched your search
@@ -214,10 +214,14 @@ class AssignGenMixin:
|
||||
"""检查最近一次 _recover_cdefine_float 是否成功"""
|
||||
return self.RecoverFound
|
||||
|
||||
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
|
||||
"""从当前模块源文件恢复浮点 CDefine 值,写入 out[0],成功返回 1
|
||||
def _recover_float_literal(self, name: str, out: t.CDouble | t.CPtr,
|
||||
require_cdefine: int) -> int:
|
||||
"""从当前模块源文件按变量名恢复浮点字面量,写入 out[0],成功返回 1
|
||||
|
||||
用输出参数传递 double,避免 TPV 跨模块 double 返回值传递 bug。
|
||||
require_cdefine=1:只认带 t.CDefine 的行(CDefine 注册路径);
|
||||
=0:模块级普通浮点全局也接受(handle_module_level_var 路径,
|
||||
如 torch `LCG_M: t.CDouble = 2147483647.0`)。
|
||||
"""
|
||||
self.RecoverFound = 0
|
||||
fp: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
@@ -252,7 +256,8 @@ class AssignGenMixin:
|
||||
if pos < total_len:
|
||||
pos += 1
|
||||
|
||||
# 匹配 "name:"
|
||||
# 匹配行首的 "name",其后(跳过空格)必须是 ':' 或 '='
|
||||
# (AnnAssign:`NAME: t.CDouble = 1.0`;无注解赋值:`NAME = 1.0`)
|
||||
if line_len < name_len + 1:
|
||||
continue
|
||||
match_ok: int = 1
|
||||
@@ -263,21 +268,27 @@ class AssignGenMixin:
|
||||
break
|
||||
if match_ok == 0:
|
||||
continue
|
||||
if buf[line_start + name_len] != ':':
|
||||
sep: t.CSizeT = line_start + name_len
|
||||
while sep < line_start + line_len and buf[sep] == ' ':
|
||||
sep += 1
|
||||
if sep >= line_start + line_len:
|
||||
continue
|
||||
if buf[sep] != ':' and buf[sep] != '=':
|
||||
continue
|
||||
|
||||
# 行内包含 "t.CDefine"
|
||||
has_cd: int = 0
|
||||
ci: t.CSizeT = line_start + name_len + 1
|
||||
while ci + 8 <= line_start + line_len:
|
||||
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
|
||||
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
|
||||
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
|
||||
has_cd = 1
|
||||
break
|
||||
ci += 1
|
||||
if has_cd == 0:
|
||||
continue
|
||||
# CDefine 路径要求行内出现 "t.CDefine";普通浮点全局路径跳过该检查
|
||||
if require_cdefine != 0:
|
||||
has_cd: int = 0
|
||||
ci: t.CSizeT = line_start + name_len + 1
|
||||
while ci + 8 <= line_start + line_len:
|
||||
if (buf[ci] == 't' and buf[ci + 1] == '.' and buf[ci + 2] == 'C' and
|
||||
buf[ci + 3] == 'D' and buf[ci + 4] == 'e' and buf[ci + 5] == 'f' and
|
||||
buf[ci + 6] == 'i' and buf[ci + 7] == 'n' and buf[ci + 8] == 'e'):
|
||||
has_cd = 1
|
||||
break
|
||||
ci += 1
|
||||
if has_cd == 0:
|
||||
continue
|
||||
|
||||
# 找 '='
|
||||
eq: t.CSizeT = line_start
|
||||
@@ -313,6 +324,10 @@ class AssignGenMixin:
|
||||
stdlib.free(buf)
|
||||
return 0
|
||||
|
||||
def _recover_cdefine_float(self, name: str, out: t.CDouble | t.CPtr) -> int:
|
||||
"""CDefine 浮点值恢复(只认带 t.CDefine 的行),见 _recover_float_literal"""
|
||||
return self._recover_float_literal(name, out, 1)
|
||||
|
||||
# ============================================================
|
||||
# _annotation_contains_name - 递归检查注解中是否包含指定名称
|
||||
#
|
||||
|
||||
@@ -1242,6 +1242,26 @@ class CallGenLeafKit(CallGenCBuiltin.CallGenCBuiltin):
|
||||
if self.Gen.TypeGenCDef.is_cdefine_found() != 0:
|
||||
kinds[di] = ast.CONST_INT
|
||||
ints[di] = cdef_v
|
||||
elif dnode is not None and dnode.kind() == ast.ASTKind.UnaryOp:
|
||||
# 一元字面量默认值(如 ex3: t.CInt = -1):AST 是
|
||||
# UnaryOp(USub, Constant(1)),不是 Constant —— 此前无此分支
|
||||
# → kinds[di] 保持 0 → 快照重建失败 → "跨模块默认参数无法
|
||||
# 重建(快照缺失,默认值需为简单常量)"(AppGui.top_index
|
||||
# 的 ex3 = -1 根因)。只对"操作数是整型 Constant"求值,
|
||||
# 其它(浮点取负 / 取负变量)保持 kinds=0 → 重建时 fail-fast。
|
||||
du: ast.UnaryOp | t.CPtr = (ast.UnaryOp | t.CPtr)(dnode)
|
||||
if du.operand is not None and du.operand.kind() == ast.ASTKind.Constant:
|
||||
doc: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(du.operand)
|
||||
if doc.const_kind == ast.CONST_INT:
|
||||
if du.op == ast.OpKind.USub:
|
||||
kinds[di] = ast.CONST_INT
|
||||
ints[di] = -doc.int_val
|
||||
elif du.op == ast.OpKind.UAdd:
|
||||
kinds[di] = ast.CONST_INT
|
||||
ints[di] = doc.int_val
|
||||
elif du.op == ast.OpKind.Invert:
|
||||
kinds[di] = ast.CONST_INT
|
||||
ints[di] = ~doc.int_val
|
||||
entry.ConstKinds = kinds
|
||||
entry.ConstInts = ints
|
||||
entry.ConstStrs = strs
|
||||
|
||||
@@ -802,16 +802,28 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
if rc_pos < total_len:
|
||||
rc_pos += 1
|
||||
|
||||
# 检查行是否以 "from ." 开头(相对导入子模块)
|
||||
# 检查行是否以 "from " 开头(模块导入)
|
||||
if rc_line_len < 12:
|
||||
continue
|
||||
if pyi_buf[rc_line_start] != 'f' or pyi_buf[rc_line_start+1] != 'r' or \
|
||||
pyi_buf[rc_line_start+2] != 'o' or pyi_buf[rc_line_start+3] != 'm' or \
|
||||
pyi_buf[rc_line_start+4] != ' ' or pyi_buf[rc_line_start+5] != '.':
|
||||
pyi_buf[rc_line_start+4] != ' ':
|
||||
continue
|
||||
|
||||
# 提取子模块名(从 rc_line_start+6 开始,到空格/tab 为止)
|
||||
rc_sub_start: t.CSizeT = rc_line_start + 6
|
||||
# 提取模块路径 token(从 rc_line_start+5 到空格/tab 为止,跳过前导点)
|
||||
# 两种写法都要支持:
|
||||
# 相对导入 `from .base import X` → 拼 base_mod.base
|
||||
# 绝对导入 `from vqt6._types import *` → 直接用 token 自身
|
||||
# 此前只认相对导入(硬要求 rc_line_start+5 是 '.'),绝对写法被
|
||||
# 直接跳过 → vqt6 包(__init__.vp 用 `from vqt6._types import *`
|
||||
# 重导出 QT_ALIGN_* 等)里的 CDefine 全部查不到 →
|
||||
# "跨模块 CDefine 未找到: 'vqt6.QT_ALIGN_CENTER'"。
|
||||
rc_is_rel: int = 0
|
||||
rc_sub_start: t.CSizeT = rc_line_start + 5
|
||||
while rc_sub_start < rc_line_start + rc_line_len and \
|
||||
pyi_buf[rc_sub_start] == '.':
|
||||
rc_is_rel = 1
|
||||
rc_sub_start += 1
|
||||
rc_sub_end: t.CSizeT = rc_sub_start
|
||||
while rc_sub_end < rc_line_start + rc_line_len and \
|
||||
pyi_buf[rc_sub_end] != ' ' and pyi_buf[rc_sub_end] != '\t':
|
||||
@@ -917,12 +929,31 @@ class ExprGenCdef(ExprGenBase.ExprGenBase):
|
||||
rc_sub_buf[rc_si] = pyi_buf[rc_sub_start + rc_si]
|
||||
rc_sub_buf[rc_sub_len] = '\0'
|
||||
|
||||
# 构建完整子模块名 base_mod.X
|
||||
rc_full_len: t.CSizeT = string.strlen(base_mod) + 1 + rc_sub_len + 1
|
||||
rc_full_mod: str = pool.alloc(rc_full_len)
|
||||
if rc_full_mod is None:
|
||||
continue
|
||||
viperlib.snprintf(rc_full_mod, rc_full_len, "%s.%s", base_mod, rc_sub_buf)
|
||||
# 构建完整模块名:
|
||||
# 相对导入(rc_is_rel=1)→ <当前模块所属包> + "." + token
|
||||
# 基准必须是"包"(rel_path 的目录部分)而不是模块名本身:
|
||||
# pkg/sub/mod.vp 里的 `from .X import Y` 指向 pkg.sub.X,
|
||||
# 用 base_mod("pkg.sub.mod")会拼成 pkg.sub.mod.X(错)。
|
||||
# __init__.vp 时包名 == 模块名,此前只在这种情况碰巧正确
|
||||
# (CallGenBase._lookup_reexport_from_vpi 用的是包名,此处对齐)。
|
||||
# 绝对导入(rc_is_rel=0)→ 直接用 token(vqt6._types)
|
||||
# 自导入(目标模块 == base_mod)跳过,避免无意义递归
|
||||
rc_full_mod: str = None
|
||||
if rc_is_rel != 0:
|
||||
rc_base_mod: str = base_mod
|
||||
rc_pkg: str = self.Gen.CallGenBase._module_package_from_sha1(pool, sha1)
|
||||
if rc_pkg is not None:
|
||||
rc_base_mod = rc_pkg
|
||||
rc_full_len: t.CSizeT = string.strlen(rc_base_mod) + 1 + rc_sub_len + 1
|
||||
rc_full_buf: str = pool.alloc(rc_full_len)
|
||||
if rc_full_buf is None:
|
||||
continue
|
||||
viperlib.snprintf(rc_full_buf, rc_full_len, "%s.%s", rc_base_mod, rc_sub_buf)
|
||||
rc_full_mod = rc_full_buf
|
||||
else:
|
||||
if string.strcmp(rc_sub_buf, base_mod) == 0:
|
||||
continue
|
||||
rc_full_mod = rc_sub_buf
|
||||
|
||||
# 防循环:若 base_mod 已以 "."+rc_sub_buf 结尾(如 ast.base 再拼
|
||||
# .base → ast.base.base),说明子模块递归在重复追加同一模块段
|
||||
|
||||
@@ -536,7 +536,8 @@ class TranslatorGenMixin:
|
||||
resolved_stg_ty: llvmlite.LLVMType | t.CPtr = None # 对象类全局:静态 storage 类型(BSS 实例)
|
||||
resolved_stg_entry: GenTypes.StructEntry | t.CPtr = None # 对象类全局:对应 StructEntry(vtable 初始化用)
|
||||
init_val: t.CInt64T = 0
|
||||
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str
|
||||
init_fval: t.CDouble = 0.0 # init_kind==4(浮点字面量)时的数值
|
||||
init_kind: int = 0 # 0=none, 1=int, 2=list, 3=str, 4=float
|
||||
init_str_val: str = None
|
||||
init_list_node: ast.List | t.CPtr = None
|
||||
# = None 显式初始化(如 tokens.vp `_kw_head: KwEntry | t.CPtr = None`):
|
||||
@@ -605,6 +606,13 @@ class TranslatorGenMixin:
|
||||
elif cn.const_kind == ast.CONST_STR:
|
||||
init_str_val = cn.str_val
|
||||
init_kind = 3
|
||||
elif cn.const_kind == ast.CONST_FLOAT:
|
||||
# 浮点字面量(如 torch `LCG_M: t.CDouble = 2147483647.0`):
|
||||
# 此前无此分支 → init_kind 保持 0 → 全局退化成
|
||||
# zeroinitializer,初始化值整体丢失(负数 -1 补在 UnaryOp
|
||||
# 分支是同一类漏项)。数值不在此处取 AST 的 float_val,
|
||||
# 见下方 init_kind==4 的源文件恢复逻辑。
|
||||
init_kind = 4
|
||||
elif val_kind == ast.ASTKind.UnaryOp:
|
||||
# 负数/按位取反字面量(如 `_vblank_ok: t.CInt = -1`):
|
||||
# AST 是 UnaryOp(USub, Constant),此前未处理 → init_kind 保持 0
|
||||
@@ -639,6 +647,11 @@ class TranslatorGenMixin:
|
||||
elif cn2.const_kind == ast.CONST_STR:
|
||||
init_str_val = cn2.str_val
|
||||
init_kind = 3
|
||||
elif cn2.const_kind == ast.CONST_FLOAT:
|
||||
# 无注解的模块级浮点赋值:字面量本身即类型依据,提升为 double
|
||||
# (默认 var_ty 是 i32,不提升会把浮点位模式写进 i32 全局)
|
||||
init_kind = 4
|
||||
var_ty = llvmlite.Double(pool)
|
||||
elif val_kind2 == ast.ASTKind.UnaryOp:
|
||||
# 负数字面量(同 AnnAssign 分支,见上):UnaryOp(USub, Constant)
|
||||
init_val = self.Gen.AssignGen.extract_cdefine_int_value(asgn.value)
|
||||
@@ -660,6 +673,30 @@ class TranslatorGenMixin:
|
||||
if string.strcmp(var_name, "__all__") == 0:
|
||||
return 0
|
||||
|
||||
# 浮点字面量初始化(init_kind==4):数值一律从当前源文件按变量名重读,
|
||||
# 不用 AST 节点的 float_val —— 该字段可能被后续 pool 操作覆写,且跨模块
|
||||
# double 返回值传递本身有缺陷(详见 AssignGenMixin._recover_float_literal)。
|
||||
# 同时校验注解类型:注解不是浮点却给浮点字面量属类型错误,直接终止,
|
||||
# 不静默零初始化。
|
||||
if init_kind == 4:
|
||||
is_fty_g: int = 0
|
||||
match var_ty:
|
||||
case llvmlite.LLVMType.Float(_):
|
||||
is_fty_g = 1
|
||||
case _:
|
||||
pass
|
||||
if is_fty_g == 0:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, f"模块级变量 '{var_name}' 用浮点字面量初始化,但注解不是浮点类型",
|
||||
"TypeError")
|
||||
return 0
|
||||
if self.Gen.AssignGen._recover_float_literal(
|
||||
var_name, t.CPtr(c.Addr(init_fval)), 0) != 1:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, f"模块级浮点变量 '{var_name}' 初始化值源文件恢复失败",
|
||||
"InternalCompilerError")
|
||||
return 0
|
||||
|
||||
# 检查是否已注册
|
||||
existing: llvmlite.Value | t.CPtr = self.Gen.VarGen.lookup_module_var(
|
||||
trans.SymTab, var_name)
|
||||
@@ -748,6 +785,19 @@ class TranslatorGenMixin:
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, f"模块级变量 '{var_name}' 初始化器构建失败", "TypeError")
|
||||
elif init_kind == 4:
|
||||
# 浮点初始值:LLVM IR 的浮点常量必须写成位模式文本(0x%016llx / 0x%08x)。
|
||||
# 十进制文本经 llc 解析对部分值有 ±1 ulp 误差(见 llvmlite.ConstFloat 注释)。
|
||||
# 此前 init_kind 没有浮点分支 → 模块级 t.CDouble 全局一律退化成
|
||||
# zeroinitializer(torch 的 LCG_A/LCG_M/_rng_state 全变 0 →
|
||||
# _next_rand() 得到 0.0/0.0 = NaN → Kaiming 初始化写入全 NaN 权重 →
|
||||
# 推理 softmax 分母 NaN → 十个概率全为 0 的根因链)。
|
||||
fc_g: llvmlite.Value | t.CPtr = llvmlite.ConstFloat(pool, var_ty, init_fval)
|
||||
if fc_g is not None and fc_g.Name is not None:
|
||||
gv.Initializer = fc_g.Name
|
||||
else:
|
||||
self.Gen.TypeGenErr.fatal_error(
|
||||
node, f"模块级变量 '{var_name}' 浮点初始化器构建失败", "TypeError")
|
||||
else:
|
||||
# 使用 zeroinitializer 而非 "0":指针类型必须用 null/zeroinitializer,
|
||||
# 整数/聚合类型也兼容 zeroinitializer,避免 "integer constant must have integer type"
|
||||
|
||||
@@ -75,8 +75,14 @@ class TypeGenBase:
|
||||
# builtins 最后匹配诊断("变量类型注解解析失败"详细报错用):
|
||||
# LastBuiltinsTypedefName = 最后一次请求的名称;LastBuiltinsTypedefResult =
|
||||
# 展开后的类型表达式(未命中 = None)。随 clear_ctypedefs 复位。
|
||||
# 两个被指串由以下自有缓冲承载(stdlib.malloc,clear_ctypedefs 释放):
|
||||
# 调用方常传临时缓冲(VpiReader._resolve_single_vpi_type_str 的段缓冲
|
||||
# malloc 后立刻 free),直接存指针会悬垂 → _build_ann_fail_msg 的
|
||||
# snprintf 读已释放内存(ASan heap-use-after-free)。
|
||||
LastBuiltinsTypedefName: str
|
||||
LastBuiltinsTypedefResult: str
|
||||
LastBuiltinsTypedefNameBuf: bytes
|
||||
LastBuiltinsTypedefResultBuf: bytes
|
||||
# builtins import 别名缓冲(stdlib.malloc,格式 "alias\0target\0" 连续段):
|
||||
# _lookup_builtins_typedef 扫描 builtins.vp import 行填充;库 typedef 模块
|
||||
# 限定引用按别名还原真实模块名(__stdint.size_t → stdint.size_t)。
|
||||
@@ -120,6 +126,8 @@ class TypeGenBase:
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
self.LastBuiltinsTypedefName = None
|
||||
self.LastBuiltinsTypedefResult = None
|
||||
self.LastBuiltinsTypedefNameBuf = None
|
||||
self.LastBuiltinsTypedefResultBuf = None
|
||||
self.ImportAliasBuf = None
|
||||
self.ConstEvalOk = 0
|
||||
self.CurrentFile = None
|
||||
|
||||
@@ -13,7 +13,10 @@ import lib.Stub.StubMerger as StubMerger
|
||||
import lib.core.CompilerFactory as CompilerFactory
|
||||
|
||||
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
import lib.core.Gen.Type.TypeGenBase as TypeGenBase
|
||||
|
||||
# builtins 诊断串自有缓冲长度(仅服务"变量类型注解解析失败"报错文本)
|
||||
TYPEDEF_DIAG_BUF: t.CDefine = 256
|
||||
|
||||
# ============================================================
|
||||
# TypeGenCType - TypeGenMixin 拆分(阶段 D):CTypedef 表(register/lookup/ScanCTypedefDeclarations/_eval_const_int_expr)
|
||||
@@ -71,6 +74,31 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
return
|
||||
self.CTypedefNames.append(name_copy)
|
||||
self.CTypedefTypeStrs.append(type_copy)
|
||||
def store_builtins_diag(self, which: int, text: str) -> str:
|
||||
"""把 builtins 诊断串复制进自有缓冲并返回该缓冲(which: 0=Name, 1=Result)
|
||||
|
||||
调用方(VpiReader._resolve_single_vpi_type_str)传的往往是
|
||||
stdlib.malloc 的临时段缓冲,返回前即 free——直接存指针会让
|
||||
_build_ann_fail_msg 的 snprintf 读已释放内存(ASan
|
||||
heap-use-after-free)。诊断字段必须持有自己的副本。
|
||||
text 为 None 时返回 None("未命中"标记)。
|
||||
"""
|
||||
if text is None:
|
||||
return None
|
||||
if which == 0:
|
||||
if self.LastBuiltinsTypedefNameBuf is None:
|
||||
self.LastBuiltinsTypedefNameBuf = stdlib.malloc(TYPEDEF_DIAG_BUF)
|
||||
buf: str = self.LastBuiltinsTypedefNameBuf
|
||||
else:
|
||||
if self.LastBuiltinsTypedefResultBuf is None:
|
||||
self.LastBuiltinsTypedefResultBuf = stdlib.malloc(TYPEDEF_DIAG_BUF)
|
||||
buf = self.LastBuiltinsTypedefResultBuf
|
||||
if buf is None:
|
||||
return None
|
||||
string.strncpy(buf, text, TYPEDEF_DIAG_BUF - 1)
|
||||
buf[TYPEDEF_DIAG_BUF - 1] = '\0'
|
||||
return buf
|
||||
|
||||
def lookup_ctypedef(self, name: str) -> str:
|
||||
"""查找 CTypedef,返回类型表达式字符串
|
||||
|
||||
@@ -105,7 +133,14 @@ class TypeGenCType(TypeGenBase.TypeGenBase):
|
||||
self.BuiltinsTypedefScanned = 0
|
||||
self.LastBuiltinsTypedefName = None
|
||||
self.LastBuiltinsTypedefResult = None
|
||||
# 别名缓冲 stdlib.malloc 分配,跨 pool 生命周期;此处释放防泄漏
|
||||
# 别名缓冲 / 诊断缓冲均为 stdlib.malloc 分配,跨 pool 生命周期;
|
||||
# 此处释放防泄漏(诊断缓冲按需再分配)
|
||||
if self.LastBuiltinsTypedefNameBuf is not None:
|
||||
stdlib.free(self.LastBuiltinsTypedefNameBuf)
|
||||
self.LastBuiltinsTypedefNameBuf = None
|
||||
if self.LastBuiltinsTypedefResultBuf is not None:
|
||||
stdlib.free(self.LastBuiltinsTypedefResultBuf)
|
||||
self.LastBuiltinsTypedefResultBuf = None
|
||||
if self.ImportAliasBuf is not None:
|
||||
stdlib.free(self.ImportAliasBuf)
|
||||
self.ImportAliasBuf = None
|
||||
|
||||
@@ -853,8 +853,13 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
"""
|
||||
if name is None:
|
||||
return None
|
||||
# 详细报错诊断:记录本次 builtins 最后匹配请求与结果(未命中 = None)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefName = name
|
||||
# 详细报错诊断:记录本次 builtins 最后匹配请求与结果(未命中 = None)。
|
||||
# 必须经 store_builtins_diag 复制进自有缓冲——name 常是调用方的临时
|
||||
# 段缓冲(VpiReader._resolve_single_vpi_type_str 的 seg_buf malloc 后
|
||||
# 立即 free),直接存指针会悬垂,_build_ann_fail_msg 的 snprintf 读已
|
||||
# 释放内存(ASan heap-use-after-free)。
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefName = \
|
||||
self.Gen.TypeGenCType.store_builtins_diag(0, name)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = None
|
||||
# rowptr 已内置于编译器(TPC/TPV 双端语法保留字,不可重定义):
|
||||
# 优先于一切外部声明(builtins.vp 已不再声明,用户自行 typedef 也会被
|
||||
@@ -866,7 +871,8 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
if ts_b is not None and self.Gen.TypeGenCType.CTypedefFound != 0:
|
||||
# 表内值可能仍是模块限定引用(如 size_t → stdint.size_t),展开后返回
|
||||
b_hit_r: str = self._expand_typedef_ref(pool, ts_b)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = b_hit_r
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = \
|
||||
self.Gen.TypeGenCType.store_builtins_diag(1, b_hit_r)
|
||||
return b_hit_r
|
||||
# 本文件已扫过 builtins 源(表内无 = 非 builtins typedef):不再重复读文件
|
||||
if self.Gen.TypeGenCType.BuiltinsTypedefScanned != 0:
|
||||
@@ -1023,10 +1029,16 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
|
||||
b_i += 1
|
||||
# 置扫描完成标记:同文件内后续 miss 直接查表,不再重复读 builtins 源
|
||||
self.Gen.TypeGenCType.BuiltinsTypedefScanned = 1
|
||||
stdlib.free(b_buf)
|
||||
# b_res 是 b_buf 内的切片(非副本),必须在 free 之前完成展开与诊断复制:
|
||||
# _expand_typedef_ref 可能原样返回指向 b_buf 的指针,free 之后再读即
|
||||
# heap-use-after-free(诊断字段还会长期持有该悬垂指针)。
|
||||
b_final_r: str = None
|
||||
if b_res is not None:
|
||||
b_final_r: str = self._expand_typedef_ref(pool, b_res)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = b_final_r
|
||||
b_final_r = self._expand_typedef_ref(pool, b_res)
|
||||
self.Gen.TypeGenCType.LastBuiltinsTypedefResult = \
|
||||
self.Gen.TypeGenCType.store_builtins_diag(1, b_final_r)
|
||||
stdlib.free(b_buf)
|
||||
if b_final_r is not None:
|
||||
return b_final_r
|
||||
return None
|
||||
def _lookup_library_typedef(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
Reference in new issue
Block a user