fix(tpv): 修复 vpi CDefine 名缓存 list.get 被误分派为 HashTable.get 的 ASan 崩溃

Converter.vp _g_pyi_cdef_names 由 list[str]|t.CPtr 改为 str|t.CPtr(i8** 字符串
指针数组),读写改用 argparse 同款可靠模式 t.CPtr(base+i*8)+e[0]:list 联合
接收者的 .get 会被分派为 HashTable.get(self, key, default),索引 inttoptr 成
key 指针传给 _fnv1a_hash 解引用零页崩溃(1.LOG)。
TranslatorGenMixin handle_module_level_var 对模块级 str|bytes 联合全局设置
IsPtrElement(8 字节指针步长),对齐 TPC global_var_ptr_element。
This commit is contained in:
TermiNexus committed 2026-08-23 12:38:25 +08:00
1 parent a12dcafed2
commit 2e6c37294d
2 files changed
+34 -11

No files matched your search

+21 -11
View File
@@ -123,10 +123,16 @@ _g_pyi_cdefine_found: int = 0
# HandlesType 全局表为空 → BinOp 内 Name 引用查表失败退化为 0(ZDEFLATE
# WINDOW_SIZE = 1<<0 = 1、MASK = 0-1 = -1,跨模块读回错误常量根因)。
# _GeneratePyiFromAst 开头按声明顺序注册到本缓存,Name 引用先查缓存。
# 值缓存用 C 数组(t.CInt64T*)而非 list[int]:TPC 对 list[int].get 会误解析为
# list[str].get(返回元素指针 i8*)→ ptrtoint 返回元素地址而非值 → MASK 变成
# 20323785277439(地址-1)。C 数组索引 [i] 直接返回 i64 值,可靠。
_g_pyi_cdef_names: list[str] | t.CPtr = None
# 缓存一律用 C 数组而非 list[T]:
# - 值缓存用 C 数组(t.CInt64T*)而非 list[int]:TPC 对 list[int].get 会误解析
# 为 list[str].get(返回元素指针 i8*)→ ptrtoint 返回元素地址而非值 → MASK
# 变成 20323785277439(地址-1)。C 数组索引 [i] 直接返回 i64 值,可靠。
# - 名缓存用 C 数组(str|t.CPtr = i8**,字符串指针数组)而非 list[str]:
# list[str] | t.CPtr 联合类型接收者的 .get 会被 TPC/TPV 误分派为
# HashTable.get(self, key, default) —— 索引被 inttoptr 成 key 指针传给
# _fnv1a_hash → 解引用零页 access-violation(1.LOG ASan 崩溃根因)。
# 读写沿用 argparse.vp 遍历 argv 的可靠模式:t.CPtr(base + i*8) + e[0]。
_g_pyi_cdef_names: str | t.CPtr = None
_g_pyi_cdef_vals: t.CInt64T | t.CPtr = None
_g_pyi_cdef_count: t.CInt = 0
@@ -137,14 +143,17 @@ def _lookup_cdefine_for_pyi(name: str) -> t.CInt64T:
# 优先查本文件 CDefine 缓存(vpi 生成早于翻译阶段注册,全局表为空)
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
# 循环上限用 _g_pyi_cdef_count 而非 len(_g_pyi_cdef_names):
# list[str] | t.CPtr 联合类型下 TPV 的 len() 回退 strlen(把 list 对象
# 指针当字符串算长度 → 垃圾小值 → 靠后注册项查不到,ZDEFLATE_HASH_MASK
# = lookup(HASH_SIZE) 失败 = 0-1 = -1 根因;WINDOW_MASK 查位置 1 恰好
# 在 strlen 结果内所以碰巧正确)。
# i8** 指针数组上 TPV 的 len() 回退 strlen(把基址指针当字符串算长度
# → 垃圾小值 → 靠后注册项查不到,ZDEFLATE_HASH_MASK = lookup(HASH_SIZE)
# 失败 = 0-1 = -1 根因;WINDOW_MASK 查位置 1 恰好落在 strlen 结果内所以
# 碰巧正确)。且绝不能对 _g_pyi_cdef_names 调 .get —— list 联合接收者
# 会被误分派为 HashTable.get,索引 inttoptr 成 key 指针读零页崩溃
# (1.LOG)。用 t.CPtr(base + i*8) + e[0] 取第 i 个名字指针(argparse 模式)。
pn: t.CSizeT = t.CSizeT(_g_pyi_cdef_count)
pi: t.CSizeT
for pi in range(pn):
pnm: str = _g_pyi_cdef_names.get(pi)
entry_pc: str | t.CPtr = t.CPtr(t.CUInt64T(_g_pyi_cdef_names) + pi * 8)
pnm: str = entry_pc[0]
if pnm is not None and string.strcmp(pnm, name) == 0:
_g_pyi_cdefine_found = 1
return _g_pyi_cdef_vals[pi]
@@ -609,7 +618,7 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
_g_pyi_cdef_count += 1
pci0 += 1
if _g_pyi_cdef_count > 0:
_g_pyi_cdef_names = list[str](mb, t.CSizeT(_g_pyi_cdef_count))
_g_pyi_cdef_names = (str | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8))
_g_pyi_cdef_vals = (t.CInt64T | t.CPtr)(mb.alloc(t.CSizeT(_g_pyi_cdef_count) * 8))
# 第二遍:按声明顺序注册(BinOp 内 Name 引用依赖先前注册项)
pci: t.CSizeT = 0
@@ -625,7 +634,8 @@ def _GeneratePyiFromAst(mb: memhub.MemBuddy | t.CPtr, tree: ast.AST | t.CPtr,
ann_pc: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(aa_pc.annotation)
if ann_pc.attr is not None and string.strcmp(ann_pc.attr, "CDefine") == 0:
if _g_pyi_cdef_names is not None and _g_pyi_cdef_vals is not None:
_g_pyi_cdef_names.append(tgt_pc.id)
slot_pc: str | t.CPtr = t.CPtr(t.CUInt64T(_g_pyi_cdef_names) + cdi * 8)
slot_pc[0] = tgt_pc.id
_g_pyi_cdef_vals[cdi] = _eval_cdefine_value_cache(aa_pc.value)
cdi += 1
pci += 1
+13
View File
@@ -572,6 +572,19 @@ class TranslatorGenMixin:
if cls_nm_ml is not None:
self.Gen.VarGen.set_var_annot_class_name(
trans.SymTab, var_name, cls_nm_ml)
# 模块级 str|t.CPtr / bytes|t.CPtr 全局:标记 IsPtrElement
# (i8** 语义,var[i] 按 8 字节指针步长),对齐 TPC 的
# global_var_ptr_element(_argv 等字符串指针数组)。否则
# var[i] 退化为 1 字节字符步长 GEP + load i8 截断指针。
if aa_ml.annotation.kind() == ast.ASTKind.BinOp:
bop_ml: ast.BinOp | t.CPtr = (ast.BinOp | t.CPtr)(aa_ml.annotation)
if bop_ml.op == ast.OpKind.BitOr:
if self.Gen.AssignGen._annotation_contains_name(
aa_ml.annotation, "str") != 0 \
or self.Gen.AssignGen._annotation_contains_name(
aa_ml.annotation, "bytes") != 0:
self.Gen.VarGen.set_var_ptr_element(
trans.SymTab, var_name)
return 1
return 0