fix(TPV): 统一浮点 CDefine 注册路径 + 1a 预扫描签名防 UAF - handle_module_level_var/PreScan 统一走 _register_cdefine_from_value(浮点/整数自动识别); 新增 register_cdefine_double/lookup_cdefine_double(%.17g 存值); translate_name_value 浮点 CDefine 返回 ConstFloat(修复 llc ret i32 0); 1a 预扫描函数签名提前泛型特化到 mark1 前(防 UAF); 移除 ASSIGN-DBG; 临时定位插桩 CDEF-DBG

This commit is contained in:
TermiNexus committed 2026-08-08 18:18:44 +08:00
1 parent aa6eee54e9
commit 24d3de4b72
5 files changed
+177 -28

No files matched your search

+30 -4
View File
@@ -122,6 +122,33 @@ def extract_cdefine_int_value(val_node: ast.AST | t.CPtr) -> int:
return 0
# ============================================================
# _register_cdefine_from_value - 注册 CDefine 常量(浮点/整数自动识别)
#
# 浮点字面量(如 vipermath 的 U_M_PI: t.CDefine = 3.14159...)走
# register_cdefine_double,否则 translate_value 查表得 0 生成
# ret i32 0(llc 报错 "value doesn't match function result type")。
# ============================================================
def _register_cdefine_from_value(pool: memhub.MemBuddy | t.CPtr,
name: str, val_node: ast.AST | t.CPtr) -> None:
"""注册 CDefine 常量(浮点字面量 → register_cdefine_double,否则整数)"""
if pool is None or name is None:
return
if val_node is not None and val_node.kind() == ast.ASTKind.Constant:
cn_fp: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(val_node)
if cn_fp.const_kind == ast.CONST_FLOAT:
# CDEF-DBG: 打印 float_val 读取(定位浮点 CDefine 值错误)
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "REG-SRC: %s kind=%d const_kind=%d int_val=%lld float_val=%.17g ptr=%p",
name, val_node.kind(), cn_fp.const_kind, cn_fp.int_val, cn_fp.float_val, t.CSizeT(cn_fp))
VLogger.info(fb_cd, "CDEF-DBG")
HandlesType.register_cdefine_double(pool, name, cn_fp.float_val)
return
val_fp: int = extract_cdefine_int_value(val_node)
HandlesType.register_cdefine_constant(pool, name, val_fp)
# ============================================================
# _annotation_contains_name - 递归检查注解中是否包含指定名称
#
@@ -284,10 +311,10 @@ class AnnAssignHandle(HandlesBase.Mixin):
# CDefine 注解: 不创建 alloca,但注册常量到全局表
# 供后续 t.CArray[elem_ty, NAME] 编译期解析使用
# 浮点/整数自动识别(与 Handle/handle_module_level_var 路径一致)
if is_cdefine_annotation(aa.annotation) != 0:
pool_ps: memhub.MemBuddy | t.CPtr = self.Trans.Pool
val_ps: int = extract_cdefine_int_value(aa.value)
HandlesType.register_cdefine_constant(pool_ps, nm.id, val_ps)
_register_cdefine_from_value(pool_ps, nm.id, aa.value)
return 0
# global/nonlocal 变量不需要局部 alloca
@@ -394,8 +421,7 @@ class AnnAssignHandle(HandlesBase.Mixin):
# 注: PreScan 已注册过,此处保证即使跳过 PreScan 也能正确注册
if is_cdefine_annotation(aa.annotation) != 0:
pool_cd: memhub.MemBuddy | t.CPtr = self.Trans.Pool
val_cd: int = extract_cdefine_int_value(aa.value)
HandlesType.register_cdefine_constant(pool_cd, nm.id, val_cd)
_register_cdefine_from_value(pool_cd, nm.id, aa.value)
return 0
pool: memhub.MemBuddy | t.CPtr = self.Trans.Pool
-12
View File
@@ -2279,10 +2279,6 @@ def _specialize_generic_class(trans: HT.Translator | t.CPtr,
type_args.set(ta_i_g, ta_rsv_g)
pool: memhub.MemBuddy | t.CPtr = trans.Pool
fb_spc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_spc is not None:
viperlib.snprintf(fb_spc, 1024, "_specialize_generic_class: %s declare_only=%d", class_name, trans._declare_only)
VLogger.info(fb_spc, "TC-DBG")
# ============================================================
# 诊断输出:追踪 GSListNode 特化调用路径
@@ -2470,10 +2466,6 @@ def translate_class_def(trans: HT.Translator | t.CPtr,
pool: memhub.MemBuddy | t.CPtr = trans.Pool
class_name: str = cd.name
fb_tcd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_tcd is not None:
viperlib.snprintf(fb_tcd, 1024, "translate_class_def: %s line=%d", class_name, cd.lineno)
VLogger.info(fb_tcd, "TC-DBG")
# 命名空间隔离:标记为当前文件可见(必须在 existing 检查之前,
# 因为 Phase B 时结构体已注册会提前 return,否则永远无法标记本地类)
@@ -3500,10 +3492,6 @@ def _translate_method(trans: HT.Translator | t.CPtr,
"""翻译单个方法,返回 0"""
if trans is None or fd is None or struct_ty is None or class_name is None:
return 0
fb_tm: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_tm is not None:
viperlib.snprintf(fb_tm, 1024, "_translate_method: %s.%s", class_name, fd.name)
VLogger.info(fb_tm, "TC-DBG")
# 懒导入
import lib.core.Handles.HandlesFunctions as HandlesFunctions
+18 -3
View File
@@ -1876,11 +1876,26 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
if nm_id is None:
return None
# CDefine 编译期常量: 直接返回整数常量值(不生成运行时代码)
# CDefine 编译期常量: 返回常量值(浮点 CDefine → double 常量,整数 → i32)
# NAME: t.CDefine = value 形式定义的常量在编译期已注册到本地表
cdef_val: int = HandlesType.lookup_cdefine_constant(nm_id)
# 浮点 CDefine(如 vipermath 的 U_M_PI=3.14...)必须返回浮点常量,
# 否则在 double 函数里 return 生成 ret i32 0(llc 报错)。
cdef_val_d: double = HandlesType.lookup_cdefine_double(nm_id)
if HandlesType.is_cdefine_found() != 0:
return llvmlite.const_int32(pool, cdef_val)
if HandlesType.is_cdefine_double() != 0:
# CDEF-DBG: 打印浮点 CDefine 使用(返回 ConstFloat)
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "USE-D: %s -> %.17g (float)", nm_id, cdef_val_d)
VLogger.info(fb_cd, "CDEF-DBG")
return llvmlite.ConstFloat(pool, llvmlite.Double(pool), cdef_val_d)
cdef_val_i: int = t.CInt(cdef_val_d)
# CDEF-DBG: 打印整数 CDefine 使用(返回 const_int32)
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "USE-I: %s -> %d (int)", nm_id, cdef_val_i)
VLogger.info(fb_cd, "CDEF-DBG")
return llvmlite.const_int32(pool, cdef_val_i)
# 本地表未找到:尝试跨模块 .vpi 查找(保证多模块查表存表一致)
# 仅对符合 CDefine 命名约定(ALL_CAPS)的名字触发跨模块查找,
+42 -6
View File
@@ -87,10 +87,6 @@ def translate_children(trans: HT.Translator | t.CPtr,
child: ast.AST | t.CPtr = ch.get(ci)
if child is None: continue
kd: int = child.kind()
fb_tc: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_tc is not None:
viperlib.snprintf(fb_tc, 1024, "translate_children[%d]: kind=%d line=%d", ci, kd, child.lineno)
VLogger.info(fb_tc, "TC-DBG")
# _declare_only == 0 时,_translate_module_level 已预处理导入语句,
# 此处跳过避免重复处理(from_imports 条目重复)
@@ -109,6 +105,13 @@ def translate_children(trans: HT.Translator | t.CPtr,
added_total += added
elif trans._declare_only == 1:
_register_cexport_from_funcdef(trans, child)
# 预解析函数签名类型,触发泛型类特化(如 numpy 的 _empty_like
# 签名 ndarray[t.CDouble] → 特化结构体注册)。
# 1a 阶段在 mark1 之前,特化结构体的 Ty/Fields 分配在 mark1 前,
# 不被 1b 的 mark/reset 回收 → 避免 Phase2 翻译 App 文件时 UAF
# (Phase1 1b 才触发特化时,结构体 Ty/Fields 在 pool 被 reset 覆写)。
# 仅触发特化,不验证结果(1b 全量翻译时仍会重新解析)。
_prescan_funcdef_signatures(trans, child)
elif kd == ast.ASTKind.ClassDef:
# ClassDef 在模块级直接处理(不需要 builder)
# _declare_only=2(import扫描模式)时跳过,只处理 import 依赖
@@ -133,6 +136,38 @@ def translate_children(trans: HT.Translator | t.CPtr,
return added_total
# ============================================================
# _prescan_funcdef_signatures - 1a 阶段预解析模块级函数签名
#
# 触发泛型类特化(如 numpy 的 _empty_like 签名 ndarray[t.CDouble]),
# 使特化结构体在 mark1 前注册(Ty/Fields 不被 1b 的 mark/reset 回收),
# 避免 Phase2 翻译 App 文件时访问悬空结构体(UAF)。
# 仅解析类型触发特化,不验证结果(1b 全量翻译时重新解析)。
# ============================================================
def _prescan_funcdef_signatures(trans: HT.Translator | t.CPtr,
fd: ast.FunctionDef | t.CPtr) -> None:
"""预解析模块级函数签名的返回/参数类型,触发泛型类特化"""
if trans is None or fd is None:
return
pool: memhub.MemBuddy | t.CPtr = trans.Pool
if pool is None:
return
imp: str = trans._imported_modules
fi: str = trans._from_imports
if fd.returns is not None:
HandlesType.resolve_annotation_type(pool, fd.returns, imp, fi, trans)
if fd.args is not None:
ags: ast.Arguments | t.CPtr = (ast.Arguments | t.CPtr)(fd.args)
if ags.args is not None:
al: list[ast.AST | t.CPtr] | t.CPtr = ags.args
an: t.CSizeT = al.__len__()
ai: t.CSizeT
for ai in range(an):
ag: ast.Arg | t.CPtr = (ast.Arg | t.CPtr)(al.get(ai))
if ag is not None and ag.annotation is not None:
HandlesType.resolve_annotation_type(pool, ag.annotation, imp, fi, trans)
# ============================================================
# _build_array_initializer_text - 从 AST List 生成 LLVM IR 数组初始化器
#
@@ -280,8 +315,9 @@ def handle_module_level_var(trans: HT.Translator | t.CPtr,
nm_cd: ast.Name | t.CPtr = (ast.Name | t.CPtr)(aa_cd.target)
if nm_cd.id is not None:
if HandlesAnnAssign.is_cdefine_annotation(aa_cd.annotation) != 0:
val_cd: int = HandlesAnnAssign.extract_cdefine_int_value(aa_cd.value)
HandlesType.register_cdefine_constant(pool, nm_cd.id, val_cd)
# 浮点/整数自动识别注册(浮点 CDefine 如 vipermath U_M_PI)
HandlesAnnAssign._register_cdefine_from_value(
pool, nm_cd.id, aa_cd.value)
return 0
# _declare_only=1(struct注册模式)时只处理 CDefine,不创建全局变量
+87 -3
View File
@@ -156,6 +156,10 @@ _g_generic_type_args: list[str] | t.CPtr = None
# ============================================================
_g_cdefine_names: list[str] | t.CPtr = None
_g_cdefine_values: list[str] | t.CPtr = None
# 浮点 CDefine 标志(1=浮点常量,值存 %f 文本;0=整数常量)
_g_cdefine_double_flags: list[int] | t.CPtr = None
# 最近一次 lookup 是否浮点 CDefine(与 _g_cdefine_found 配合)
_g_cdefine_is_double: int = 0
# ============================================================
# 当前模块 SHA1(Phase1 在模块开始翻译前设置,供报错使用)
@@ -176,10 +180,11 @@ def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
值以十进制字符串存储。注意:value 是 32 位有符号整数,
0xFFFFFFFF 会存储为 "-1",lookup 时用 found 标志区分"未找到"和值为 -1。
"""
global _g_cdefine_names, _g_cdefine_values
global _g_cdefine_names, _g_cdefine_values, _g_cdefine_double_flags
if _g_cdefine_names is None:
_g_cdefine_names = list[str](pool, 64)
_g_cdefine_values = list[str](pool, 64)
_g_cdefine_double_flags = list[int](pool, 64)
_g_cdefine_names.append(name)
val_buf: str = pool.alloc(32)
if val_buf is not None:
@@ -187,6 +192,36 @@ def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
_g_cdefine_values.append(val_buf)
else:
_g_cdefine_values.append("0")
if _g_cdefine_double_flags is not None:
_g_cdefine_double_flags.append(0)
def register_cdefine_double(pool: memhub.MemBuddy | t.CPtr,
name: str, value: double) -> None:
"""注册浮点 CDefine 编译期常量(如 U_M_PI: t.CDefine = 3.14159...)
值以 %f 文本存储并标记浮点,供 translate_value 返回浮点常量。
"""
global _g_cdefine_names, _g_cdefine_values, _g_cdefine_double_flags
if _g_cdefine_names is None:
_g_cdefine_names = list[str](pool, 64)
_g_cdefine_values = list[str](pool, 64)
_g_cdefine_double_flags = list[int](pool, 64)
_g_cdefine_names.append(name)
val_buf: str = pool.alloc(32)
if val_buf is not None:
viperlib.snprintf(val_buf, 32, "%.17g", value)
_g_cdefine_values.append(val_buf)
else:
_g_cdefine_values.append("0")
if _g_cdefine_double_flags is not None:
_g_cdefine_double_flags.append(1)
# CDEF-DBG: 打印注册的浮点 CDefine(定位 llc ret i32 0)
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "REG-D: %s = %.17g (buf=%s)",
name, value, val_buf if val_buf is not None else "(null)")
VLogger.info(fb_cd, "CDEF-DBG")
def lookup_cdefine_constant(name: str) -> int:
@@ -195,9 +230,11 @@ def lookup_cdefine_constant(name: str) -> int:
返回找到的值。由于 -1 是合法值(如 INVALID_HANDLE_VALUE=0xFFFFFFFF=-1),
用全局 _g_cdefine_found 标志区分"未找到"和值为 -1。
调用方应在调用后检查 _g_cdefine_found。
浮点 CDefine 项返回整数部分(与 _g_cdefine_is_double 标志配合)。
"""
global _g_cdefine_found
global _g_cdefine_found, _g_cdefine_is_double
_g_cdefine_found = 0
_g_cdefine_is_double = 0
if _g_cdefine_names is None:
return 0
n: t.CSizeT = _g_cdefine_names.__len__()
@@ -208,10 +245,56 @@ def lookup_cdefine_constant(name: str) -> int:
val_str: str = _g_cdefine_values.get(i)
if val_str is not None:
_g_cdefine_found = 1
if _g_cdefine_double_flags is not None and _g_cdefine_double_flags.get(i) == 1:
_g_cdefine_is_double = 1
return string.atoi(val_str)
return string.atoi(val_str)
return 0
def lookup_cdefine_double(name: str) -> double:
"""查找 CDefine 编译期常量,返回 double 值(浮点/整数统一)
与 lookup_cdefine_constant 共享 _g_cdefine_found / _g_cdefine_is_double
(found=1 且 is_double=1 → 浮点 CDefine,应返回浮点常量)。
"""
global _g_cdefine_found, _g_cdefine_is_double
_g_cdefine_found = 0
_g_cdefine_is_double = 0
if _g_cdefine_names is None:
return 0.0
n: t.CSizeT = _g_cdefine_names.__len__()
i: t.CSizeT
for i in range(n):
nm: str = _g_cdefine_names.get(i)
if nm is not None and string.strcmp(nm, name) == 0:
val_str: str = _g_cdefine_values.get(i)
if val_str is not None:
_g_cdefine_found = 1
if _g_cdefine_double_flags is not None and _g_cdefine_double_flags.get(i) == 1:
_g_cdefine_is_double = 1
ret_d: double = string.atof(val_str)
# CDEF-DBG: 打印浮点查找命中
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "LOOKUP-D: %s -> buf=%s atof=%.17g", name, val_str, ret_d)
VLogger.info(fb_cd, "CDEF-DBG")
return ret_d
ret_i2: double = double(string.atoi(val_str))
# CDEF-DBG: 打印整数查找命中
fb_cd: t.CChar | t.CPtr = VLogger.fmt_buf()
if fb_cd is not None:
viperlib.snprintf(fb_cd, 1024, "LOOKUP-I: %s -> buf=%s atoi=%d", name, val_str, string.atoi(val_str))
VLogger.info(fb_cd, "CDEF-DBG")
return ret_i2
return 0.0
def is_cdefine_double() -> int:
"""检查最近一次 CDefine 查找命中的是否是浮点常量"""
return _g_cdefine_is_double
_g_cdefine_found: int = 0
@@ -228,9 +311,10 @@ def set_cdefine_found(val: int) -> None:
def clear_cdefine_constants() -> None:
"""清空 CDefine 常量表(模块切换时调用)"""
global _g_cdefine_names, _g_cdefine_values
global _g_cdefine_names, _g_cdefine_values, _g_cdefine_double_flags
_g_cdefine_names = None
_g_cdefine_values = None
_g_cdefine_double_flags = None
# ============================================================