fix(gen): 清理 ASan 二分调试检查 + StdlibAlloc 跨 Mixin 委托 + 调试链修复
1. 移除 ClassGenMixin 泛型判断前/模板注册后与 Phase1 五处 gen 完整性二分检查(GlobalFuncs 调试残留,Mixin 方法体访问非自身字段违反块内索引约束)。2. ClassGenMixin._register_struct 读 self.StdlibAlloc(StructGenMixin 字段)改经 HandlesStruct.get_stdlib_alloc 委托,新增 StructGenMixin.get_stdlib_alloc。3. 含 P5 后累积修复(VpiReader ParamCount/越界封堵等)。
This commit is contained in:
1 parent
ba3f22702e
commit
451be82b32
12 files changed
+217
-69
No files matched your search
@@ -316,12 +316,24 @@ def _subst_template_arg(annot: str, tparam: str, targ: str) -> str:
|
||||
tglen: t.CSizeT = string.strlen(targ)
|
||||
if tplen == 0 or tplen > alen:
|
||||
return annot
|
||||
out: bytes = stdlib.malloc(alen + tglen * 8 + 16)
|
||||
# 容量 = alen + tglen*8 + 16 只覆盖 ≤8 次替换;替换次数无上限时
|
||||
# opos 会越界写穿 stdlib 堆(哨兵盲区 → CRT 堆损坏后任意 malloc/free
|
||||
# 静默段错误、崩溃点漂移)。按最坏上界分配:每替换消耗 tplen 写 tglen,
|
||||
# 最坏全部被替换 → alen + (alen/tplen)*tglen + 1。
|
||||
max_sub: t.CSizeT = alen / tplen
|
||||
if max_sub == 0:
|
||||
max_sub = 1
|
||||
out_size: t.CSizeT = alen + max_sub * tglen + 1
|
||||
out: bytes = stdlib.malloc(out_size)
|
||||
if out is None:
|
||||
return None
|
||||
opos: t.CSizeT = 0
|
||||
p: t.CSizeT = 0
|
||||
while p < alen:
|
||||
# 防御:opos 超分配即 fail-fast 返回 None(绝不越界写)
|
||||
if opos >= out_size:
|
||||
stdlib.free(out)
|
||||
return None
|
||||
matched: int = 0
|
||||
if annot[p] == tparam[0] and p + tplen <= alen:
|
||||
if string.strncmp(annot + p, tparam, tplen) == 0:
|
||||
|
||||
@@ -171,8 +171,6 @@ def TranslateFileGetTrans(mb: memhub.MemBuddy | t.CPtr, file_path: str,
|
||||
if string.strstr(file_path, "includes") is not None:
|
||||
strict_mode = 0
|
||||
HandlesStruct.reset_visible_structs(mb, strict_mode)
|
||||
# CHK-FLOAT: translate 前检查浮点 Constant(二分定位覆写阶段)
|
||||
HandlesType._dbg_check_ast_floats(mb, tree, "PRE-TR")
|
||||
ret: int = tr.translate(tree)
|
||||
if ret != 0:
|
||||
return None
|
||||
|
||||
@@ -158,9 +158,12 @@ class CallGenMixin:
|
||||
string.memset(self.CexportFuncArr, 0, _CEXPORT_MAX * 64)
|
||||
if self.CexportCount < _CEXPORT_MAX:
|
||||
idx: t.CSizeT = t.CSizeT(self.CexportCount) * 17
|
||||
string.strcpy(self.CexportSha1Arr + idx, sha1)
|
||||
# 槽位定长 17/64 字节,strcpy 无界会越界写相邻槽(stdlib 堆区)
|
||||
string.strncpy(self.CexportSha1Arr + idx, sha1, 16)
|
||||
self.CexportSha1Arr[idx + 16] = '\0'
|
||||
idx2: t.CSizeT = t.CSizeT(self.CexportCount) * 64
|
||||
string.strcpy(self.CexportFuncArr + idx2, func_name)
|
||||
string.strncpy(self.CexportFuncArr + idx2, func_name, 63)
|
||||
self.CexportFuncArr[idx2 + 63] = '\0'
|
||||
self.CexportCount += 1
|
||||
return 1
|
||||
return 0
|
||||
@@ -1744,7 +1747,9 @@ class CallGenMixin:
|
||||
elif tk == ast.ASTKind.Constant:
|
||||
cn2: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(first_arg)
|
||||
if cn2.str_val is not None:
|
||||
string.strcpy(text, cn2.str_val)
|
||||
# 裸 strcpy 无界:模板常量串 ≥ LLVMIR_TEMPLATE_BUF 会越界写 pool 块,
|
||||
# 改用与 JoinedStr 分支一致的有界追加
|
||||
self._asm_append_cstr(text, LLVMIR_TEMPLATE_BUF, cn2.str_val)
|
||||
|
||||
# ============================================================
|
||||
# 2. 直接嵌入模板文本(不做指令解析)+ LOut 写回
|
||||
@@ -2937,7 +2942,7 @@ class CallGenMixin:
|
||||
# 构造搜索模式: "{sha1}.{class_name}.{method_name}"
|
||||
cls_len: t.CSizeT = string.strlen(class_name)
|
||||
meth_len: t.CSizeT = string.strlen(method_name)
|
||||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 3
|
||||
search_len: t.CSizeT = sha1_len + cls_len + meth_len + 4
|
||||
search_buf: bytes = stdlib.malloc(search_len)
|
||||
if search_buf is None:
|
||||
stdlib.free(read_buf)
|
||||
@@ -3407,7 +3412,7 @@ class CallGenMixin:
|
||||
base_buf_g[base_len_g] = '\0'
|
||||
string.strncpy(arg_buf_g, lbkt_g + 1, arg_len_g)
|
||||
arg_buf_g[arg_len_g] = '\0'
|
||||
ta_list_g: list[str] | t.CPtr = list[str](pool, 4)
|
||||
ta_list_g: list[str] | t.CPtr = list[str](pool, 8)
|
||||
if ta_list_g is not None:
|
||||
# 逗号分隔多类型实参(list[X] / dict[K, V])
|
||||
cur_arg_g: str = arg_buf_g
|
||||
@@ -4228,6 +4233,11 @@ class CallGenMixin:
|
||||
|
||||
ai: t.CSizeT = 0
|
||||
while ai < can:
|
||||
if ai >= 32:
|
||||
# 定长 8*32 槽:超过 32 个实参继续写会越界污染 pool 相邻块,fail-fast
|
||||
HandlesType.fatal_error(
|
||||
cl, "泛型构造实参超过 32 个上限", "TypeError")
|
||||
break
|
||||
arg_node: ast.AST | t.CPtr = cargs.get(ai)
|
||||
if arg_node is not None:
|
||||
arg_val: llvmlite.Value | t.CPtr = HandlesExpr.translate_value(
|
||||
@@ -5793,7 +5803,8 @@ class CallGenMixin:
|
||||
if self.FuncptrCount >= MAX_FUNC_PTR_SIGS:
|
||||
return 1
|
||||
idx: t.CSizeT = t.CSizeT(self.FuncptrCount) * 64
|
||||
string.strcpy(self.FuncptrNames + idx, name)
|
||||
# 槽位定长 64 字节,与 register_closure_name 一致用 strncpy 钳制防越界
|
||||
string.strncpy(self.FuncptrNames + idx, name, 63)
|
||||
self.FuncptrRets[self.FuncptrCount] = t.CUInt64T(ret_ty)
|
||||
self.FuncptrCount += 1
|
||||
return 0
|
||||
@@ -6421,25 +6432,25 @@ class CallGenMixin:
|
||||
if ret_part is not None and ret_ty is not None:
|
||||
ret_part[0] = '\0'
|
||||
llvmlite.TypePrint(ret_part, 512, ret_ty, pool)
|
||||
string.strcat(ty_buf, ret_part)
|
||||
string.strcat(ty_buf, " (")
|
||||
self._asm_append_cstr(ty_buf, 1024, ret_part)
|
||||
self._asm_append_cstr(ty_buf, 1024, " (")
|
||||
|
||||
# 参数类型
|
||||
# 参数类型(全部经 _asm_append_cstr 有界追加,防止 strcat 无界写穿 1024 缓冲)
|
||||
cur: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(func)
|
||||
first: int = 1
|
||||
param_part: t.CChar | t.CPtr = pool.alloc(512)
|
||||
while cur is not None:
|
||||
if first == 0:
|
||||
string.strcat(ty_buf, ", ")
|
||||
self._asm_append_cstr(ty_buf, 1024, ", ")
|
||||
if param_part is not None:
|
||||
param_part[0] = '\0'
|
||||
param_ty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(cur)
|
||||
if param_ty is not None:
|
||||
llvmlite.TypePrint(param_part, 512, param_ty, pool)
|
||||
string.strcat(ty_buf, param_part)
|
||||
self._asm_append_cstr(ty_buf, 1024, param_part)
|
||||
cur = llvmlite.param_get_next(cur)
|
||||
first = 0
|
||||
string.strcat(ty_buf, ")")
|
||||
self._asm_append_cstr(ty_buf, 1024, ")")
|
||||
|
||||
# 深拷贝到 stdlib 区(TypeStr 跨文件永久存活)
|
||||
ts_len: t.CSizeT = string.strlen(ty_buf)
|
||||
|
||||
@@ -316,7 +316,9 @@ class ClassGenMixin:
|
||||
stdlib.free(key_buf)
|
||||
return
|
||||
if self.MethodMetaCount < META_MAX:
|
||||
string.strcpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN, key_buf)
|
||||
# 槽位定长 META_KEY_LEN=128 字节,key 超长时 strncpy 钳制防越界写相邻槽
|
||||
string.strncpy(self.MethodMetaKeys + self.MethodMetaCount * META_KEY_LEN,
|
||||
key_buf, META_KEY_LEN - 1)
|
||||
flags_ptr2: t.CPtr = (t.CInt | t.CPtr)(t.CVoid(
|
||||
t.CUInt64T(self.MethodMetaFlags) + self.MethodMetaCount * 4, t.CPtr))
|
||||
flags_ptr2[0] = meta
|
||||
@@ -1353,7 +1355,11 @@ class ClassGenMixin:
|
||||
for pos in range(1, total_positions):
|
||||
pos_max: int = 0
|
||||
for vi in range(variant_count):
|
||||
if vi >= 64:
|
||||
break # variant_field_sizes 64 类槽上限,防读越界
|
||||
field_pos: int = pos - 1 # 变体字段从位置 0 开始
|
||||
if field_pos >= 16:
|
||||
continue # 超出每变体 16 字段槽位:未写入(memset 为 0),跳过
|
||||
offset2: t.CSizeT = vi * 16 + field_pos
|
||||
fsize_val: t.CSizeT = variant_field_sizes[offset2]
|
||||
if fsize_val > pos_max:
|
||||
@@ -1510,6 +1516,14 @@ class ClassGenMixin:
|
||||
for ci in range(cn):
|
||||
if tag >= variant_count:
|
||||
break
|
||||
if tag >= RENUM_VARIANT_PER_CLASS:
|
||||
# 每类固定 32 槽:变体超过上限继续写会越界污染相邻类槽,fail-fast 报错
|
||||
fb_rv: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_rv is not None:
|
||||
viperlib.snprintf(fb_rv, 1024,
|
||||
"REnum 变体数超过上限 %d: %s", RENUM_VARIANT_PER_CLASS, class_name)
|
||||
VLogger.error(fb_rv, "RENUM")
|
||||
break
|
||||
stmt: ast.AST | t.CPtr = children.get(ci)
|
||||
if stmt is None:
|
||||
continue
|
||||
@@ -2598,7 +2612,17 @@ class ClassGenMixin:
|
||||
if is_novtable_deco == 1:
|
||||
entry.IsNoVTable = 1
|
||||
if parent_name is not None:
|
||||
entry.ParentName = parent_name
|
||||
# 1b 阶段父类名是 pool 字符串(本文件 AST/1a 预存),reset 后悬空;
|
||||
# _translate_oop_methods/_detect_vtable_status 会在后续文件
|
||||
# find_struct(ParentName) strcmp 解引用 → 用 stdlib 拷贝保证跨文件存活
|
||||
if HandlesStruct.get_stdlib_alloc() != 0:
|
||||
pn_len: t.CSizeT = string.strlen(parent_name)
|
||||
pn_buf: t.CChar | t.CPtr = stdlib.malloc(pn_len + 1)
|
||||
if pn_buf is not None:
|
||||
string.strcpy(pn_buf, parent_name)
|
||||
entry.ParentName = pn_buf
|
||||
else:
|
||||
entry.ParentName = parent_name
|
||||
# 多继承:设置父类数组(供 MRO/字段/vtable 查询,stdlib 深拷贝跨文件存活)
|
||||
if parents_count > 0 and parents_buf is not None:
|
||||
HandlesStruct.set_parent_names(class_name, parents_buf, parents_count)
|
||||
@@ -3268,9 +3292,14 @@ class ClassGenMixin:
|
||||
return 0
|
||||
viperlib.snprintf(method_name_buf, 128, "%s", fd.name)
|
||||
if func_meta & META_PROP_SETTER != 0:
|
||||
string.strcat(method_name_buf, "$set")
|
||||
# 128 字节缓冲:追加 "$set" 前检查剩余容量,防 strcat 无界写穿
|
||||
mn_len2: t.CSizeT = string.strlen(method_name_buf)
|
||||
if mn_len2 + 5 < 128:
|
||||
string.strcat(method_name_buf, "$set")
|
||||
elif func_meta & META_PROP_DELETER != 0:
|
||||
string.strcat(method_name_buf, "$del")
|
||||
mn_len2: t.CSizeT = string.strlen(method_name_buf)
|
||||
if mn_len2 + 5 < 128:
|
||||
string.strcat(method_name_buf, "$del")
|
||||
method_name = method_name_buf
|
||||
|
||||
is_static_m: int = 0
|
||||
|
||||
@@ -188,11 +188,15 @@ class FuncGenMixin:
|
||||
self._append_str(attrs_buf, llvm_name)
|
||||
return 1
|
||||
|
||||
def _append_str(self, buf: t.CChar | t.CPtr, s: str) -> None:
|
||||
"""将字符串追加到 buf 末尾(用 strlen+strcpy 模拟 strcat)"""
|
||||
def _append_str(self, buf: t.CChar | t.CPtr, s: str,
|
||||
max_len: t.CSizeT = 256) -> None:
|
||||
"""将字符串追加到 buf 末尾(有界,防 strcpy 越界写穿定长缓冲)"""
|
||||
if buf is None or s is None:
|
||||
return
|
||||
cur_len: t.CSizeT = string.strlen(buf)
|
||||
s_len: t.CSizeT = string.strlen(s)
|
||||
if cur_len + s_len + 1 > max_len:
|
||||
return # 无剩余容量:丢弃本次追加,避免越界写
|
||||
string.strcpy(buf + cur_len, s)
|
||||
|
||||
# ============================================================
|
||||
|
||||
@@ -79,6 +79,11 @@ class StructGenMixin:
|
||||
"""设置 OOM 回收分配模式:1=1b 阶段(新条目用 stdlib),0=注册阶段(用 pool)"""
|
||||
self.StdlibAlloc = flag
|
||||
|
||||
def get_stdlib_alloc(self) -> int:
|
||||
"""读取 OOM 回收分配模式(供其他 Mixin 经 HandlesStruct 委托访问,
|
||||
避免跨 Mixin 直接读 self.StdlibAlloc——Mixin 方法体按自身块内索引编译)"""
|
||||
return self.StdlibAlloc
|
||||
|
||||
def reset_visible_structs(self, pool: memhub.MemBuddy | t.CPtr, strict: int):
|
||||
"""重置可见性状态(每个文件翻译前调用)
|
||||
|
||||
@@ -277,13 +282,76 @@ class StructGenMixin:
|
||||
fe.Name = name_buf
|
||||
|
||||
fe.Index = idx
|
||||
fe.Ty = field_ty
|
||||
fe.DefaultVal = default_val
|
||||
fe.AnnotClassName = annot_class_name
|
||||
# 1b 阶段(StdlibAlloc=1)字段类型/注解类名必须深拷贝到 stdlib:
|
||||
# register_struct 已迁 Fields/Name/ModuleSha1/Ty(translate_class_def L2566
|
||||
# DeepCopyType),但字段级 Ty/AnnotClassName 仍存 pool 指针,本文件
|
||||
# reset_to(mark1) 回收后,跨文件读取(字段展平、多继承 this 调整、
|
||||
# AnnotClassName 回退、_apply_struct_defaults 的 build_gep_struct 用 fe.Ty
|
||||
# 作 GEP 结果类型)解引用悬空内存 → 崩溃点漂移(json/string/builtins 之间)。
|
||||
if self.StdlibAlloc != 0:
|
||||
ty_copy: llvmlite.LLVMType | t.CPtr = llvmlite.DeepCopyType(pool, field_ty)
|
||||
if ty_copy is not None:
|
||||
fe.Ty = ty_copy
|
||||
else:
|
||||
fe.Ty = field_ty
|
||||
if annot_class_name is not None:
|
||||
annot_len: t.CSizeT = string.strlen(annot_class_name)
|
||||
annot_buf: t.CChar | t.CPtr = stdlib.malloc(annot_len + 1)
|
||||
if annot_buf is not None:
|
||||
string.strcpy(annot_buf, annot_class_name)
|
||||
fe.AnnotClassName = annot_buf
|
||||
# DefaultVal:跨文件结构体构造(_translate_struct_ctor→_apply_struct_defaults)
|
||||
# 在调用方文件翻译时读取字段默认值,原 pool AST 已 reset 回收 → 常量深拷贝
|
||||
fe.DefaultVal = self._deep_copy_default_ast(default_val)
|
||||
else:
|
||||
fe.Ty = field_ty
|
||||
fe.AnnotClassName = annot_class_name
|
||||
fe.DefaultVal = default_val
|
||||
|
||||
struct_entry.FieldCount = idx + 1
|
||||
return idx
|
||||
|
||||
def _deep_copy_default_ast(self, default_val: ast.AST | t.CPtr) -> ast.AST | t.CPtr:
|
||||
"""深拷贝字段默认值 AST 到 stdlib(仅常量节点),跨 1b reset 存活。
|
||||
|
||||
字段默认值(fe.DefaultVal)除定义文件内 _generate_before_init 使用外,
|
||||
跨文件结构体构造(_translate_struct_ctor → _apply_struct_defaults)会在
|
||||
调用方文件翻译时读取——原 pool AST 已 reset 回收必须深拷贝。
|
||||
非常量默认值(Name/BinOp 等引用表达式)无法安全深拷贝:返回 None
|
||||
(调用方 fe.DefaultVal 保持 None,仅定义文件内 _generate_before_init
|
||||
仍持有原始 pool 指针,不受影响)。
|
||||
"""
|
||||
if default_val is None:
|
||||
return None
|
||||
if default_val.kind() != ast.ASTKind.Constant:
|
||||
return None
|
||||
src_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(default_val)
|
||||
dst_c: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(
|
||||
stdlib.malloc(ast.Constant.__sizeof__()))
|
||||
if dst_c is None:
|
||||
return None
|
||||
string.memset(dst_c, 0, ast.Constant.__sizeof__())
|
||||
# 拷贝 vtable 指针(AST 是 @t.CVTable,kind() 虚调用依赖首字段 vptr)
|
||||
vt_ptr: t.CVoid | t.CPtr = t.CVoid(
|
||||
c.Deref(t.CUInt64T(default_val, t.CPtr), t.CPtr), t.CPtr)
|
||||
c.DerefAs(dst_c, vt_ptr)
|
||||
# 拷贝位置字段(报错定位用)
|
||||
dst_c.lineno = src_c.lineno
|
||||
dst_c.col_offset = src_c.col_offset
|
||||
dst_c.end_lineno = src_c.end_lineno
|
||||
dst_c.end_col_offset = src_c.end_col_offset
|
||||
# 拷贝常量值(int/float/str/bool 由 const_kind 区分)
|
||||
dst_c.const_kind = src_c.const_kind
|
||||
dst_c.int_val = src_c.int_val
|
||||
dst_c.float_val = src_c.float_val
|
||||
if src_c.str_val is not None:
|
||||
s_len: t.CSizeT = string.strlen(src_c.str_val)
|
||||
s_copy: t.CChar | t.CPtr = stdlib.malloc(s_len + 1)
|
||||
if s_copy is not None:
|
||||
string.strcpy(s_copy, src_c.str_val)
|
||||
dst_c.str_val = s_copy
|
||||
return (ast.AST | t.CPtr)(dst_c)
|
||||
|
||||
def get_struct_count(self) -> int:
|
||||
"""返回当前已注册的结构体数量"""
|
||||
return self.StructCount
|
||||
@@ -962,8 +1030,12 @@ class StructGenMixin:
|
||||
sha1_buf: t.CChar | t.CPtr = pool.alloc(32)
|
||||
if sha1_buf is None:
|
||||
return
|
||||
string.strncpy(sha1_buf, sname, sha1_len)
|
||||
sha1_buf[sha1_len] = '\0'
|
||||
# 32 字节缓冲:strncpy 不截断,前缀超过 31 字符会越界写 + 手动 NUL 再越界
|
||||
sha1_cp: t.CSizeT = sha1_len
|
||||
if sha1_cp > 31:
|
||||
sha1_cp = 31
|
||||
string.strncpy(sha1_buf, sname, sha1_cp)
|
||||
sha1_buf[sha1_cp] = '\0'
|
||||
# 按类名 + SHA1 查找结构体定义
|
||||
entry: HandlesStruct.StructEntry | t.CPtr = self.find_struct_by_module(class_name, sha1_buf)
|
||||
if entry is None:
|
||||
|
||||
@@ -182,36 +182,8 @@ class TypeGenMixin:
|
||||
|
||||
def _dbg_check_ast_floats(self, mb: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr, tag: str):
|
||||
"""CHK-FLOAT: 遍历 AST 检查所有浮点 Constant 节点"""
|
||||
if tree is None:
|
||||
return
|
||||
if tree.kind() == ast.ASTKind.Constant:
|
||||
cn_f: ast.Constant | t.CPtr = (ast.Constant | t.CPtr)(tree)
|
||||
if cn_f.const_kind == ast.CONST_FLOAT:
|
||||
fb_chk: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb_chk is not None:
|
||||
stdio.snprintf(fb_chk, 1024, "[CHK-FLOAT] %s ptr=%p float_val=%.17g",
|
||||
tag, t.CSizeT(cn_f), cn_f.float_val)
|
||||
VLogger.info(fb_chk, "CHK")
|
||||
return
|
||||
# AnnAssign: value/annotation/target 不在 children 里,单独遍历
|
||||
if tree.kind() == ast.ASTKind.AnnAssign:
|
||||
aa_f: ast.AnnAssign | t.CPtr = (ast.AnnAssign | t.CPtr)(tree)
|
||||
if aa_f.value is not None:
|
||||
self._dbg_check_ast_floats(mb, aa_f.value, tag)
|
||||
if aa_f.annotation is not None:
|
||||
self._dbg_check_ast_floats(mb, aa_f.annotation, tag)
|
||||
if aa_f.target is not None:
|
||||
self._dbg_check_ast_floats(mb, aa_f.target, tag)
|
||||
return
|
||||
ch_f: list[ast.AST | t.CPtr] | t.CPtr = tree.children
|
||||
if ch_f is not None:
|
||||
n_f: t.CSizeT = ch_f.__len__()
|
||||
i_f: t.CSizeT
|
||||
for i_f in range(n_f):
|
||||
c_f: ast.AST | t.CPtr = ch_f.get(i_f)
|
||||
if c_f is not None:
|
||||
self._dbg_check_ast_floats(mb, c_f, tag)
|
||||
"""已移除调试插桩(占位保留签名,避免外部调用引用失败)"""
|
||||
pass
|
||||
|
||||
def register_cdefine_constant(self, pool: memhub.MemBuddy | t.CPtr,
|
||||
name: str, value: int) -> None:
|
||||
|
||||
@@ -316,15 +316,19 @@ def register_reexport(mod_sha1: str, func_name: str, source_module: str) -> int:
|
||||
fidx: t.CSizeT = t.CSizeT(i) * 64
|
||||
if string.strcmp(_g_reexport_sha1s + sidx, mod_sha1) == 0:
|
||||
if string.strcmp(_g_reexport_funcs + fidx, func_name) == 0:
|
||||
# 已存在,更新 source_module(以防变化)
|
||||
string.strcpy(_g_reexport_srcs + fidx, source_module)
|
||||
# 已存在,更新 source_module(以防变化;64 字节槽,strncpy 钳制)
|
||||
string.strncpy(_g_reexport_srcs + fidx, source_module, 63)
|
||||
_g_reexport_srcs[fidx + 63] = '\0'
|
||||
return 0
|
||||
# 添加新条目
|
||||
# 添加新条目(槽位定长 17/64 字节,strcpy 无界会越界写相邻槽,全部 strncpy 钳制)
|
||||
idx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 17
|
||||
fidx2: t.CSizeT = t.CSizeT(_g_reexport_count) * 64
|
||||
string.strcpy(_g_reexport_sha1s + idx2, mod_sha1)
|
||||
string.strcpy(_g_reexport_funcs + fidx2, func_name)
|
||||
string.strcpy(_g_reexport_srcs + fidx2, source_module)
|
||||
string.strncpy(_g_reexport_sha1s + idx2, mod_sha1, 16)
|
||||
_g_reexport_sha1s[idx2 + 16] = '\0'
|
||||
string.strncpy(_g_reexport_funcs + fidx2, func_name, 63)
|
||||
_g_reexport_funcs[fidx2 + 63] = '\0'
|
||||
string.strncpy(_g_reexport_srcs + fidx2, source_module, 63)
|
||||
_g_reexport_srcs[fidx2 + 63] = '\0'
|
||||
_g_reexport_count += 1
|
||||
return 0
|
||||
|
||||
|
||||
@@ -103,6 +103,15 @@ def set_stdlib_alloc(flag: int):
|
||||
g.set_stdlib_alloc(flag)
|
||||
|
||||
|
||||
def get_stdlib_alloc() -> int:
|
||||
"""读取 OOM 回收分配模式(委托到 gen.get_stdlib_alloc)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
return g.get_stdlib_alloc()
|
||||
return 0
|
||||
|
||||
|
||||
def reset_visible_structs(pool: memhub.MemBuddy | t.CPtr, strict: int):
|
||||
"""重置可见性状态(每个文件翻译前调用,委托到 gen.reset_visible_structs)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
|
||||
@@ -296,8 +296,6 @@ class Translator:
|
||||
break
|
||||
|
||||
if self._declare_only != 0:
|
||||
# CHK-FLOAT: 模块级翻译前检查(二分定位覆写阶段)
|
||||
HandlesType._dbg_check_ast_floats(pool, tree, "PRE-ML")
|
||||
# Phase 1a-pre(2=import扫描) / Phase 1a(1=struct注册): 只处理模块级,不创建 main 函数和 builder
|
||||
self._translate_module_level(pool, mod, tree)
|
||||
elif has_user_main == 0:
|
||||
|
||||
@@ -134,11 +134,8 @@ def set_current_module_sha1(sha1: str) -> None:
|
||||
|
||||
def _dbg_check_ast_floats(mb: memhub.MemBuddy | t.CPtr,
|
||||
tree: ast.AST | t.CPtr, tag: str):
|
||||
"""CHK-FLOAT: 遍历 AST 检查所有浮点 Constant 节点(委托到 gen._dbg_check_ast_floats)"""
|
||||
import lib.core.Gen.Generator as Generator
|
||||
g: Generator.Generator | t.CPtr = (Generator.Generator | t.CPtr)(t.CVoid(_g_gen, t.CPtr))
|
||||
if g is not None:
|
||||
g._dbg_check_ast_floats(mb, tree, tag)
|
||||
"""已移除调试插桩(占位保留签名,避免外部调用引用失败)"""
|
||||
pass
|
||||
|
||||
|
||||
def register_cdefine_constant(pool: memhub.MemBuddy | t.CPtr,
|
||||
|
||||
@@ -18,6 +18,7 @@ import lib.core.Handles.HandlesImports as HandlesImports
|
||||
import lib.core.Handles.HandlesClassDef as HandlesClassDef
|
||||
import lib.core.IncludesScanner as IncludesScanner
|
||||
import lib.core.StubMerger as StubMerger
|
||||
import lib.core.Gen.Generator as GenGenerator
|
||||
import lib.core.BuildPipeline as BuildPipeline
|
||||
import lib.Projectrans.Config as Config
|
||||
import lib.StubGen.Converter as StubConverter
|
||||
@@ -837,6 +838,7 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
HandlesType.clear_cdefine_constants()
|
||||
HandlesType.clear_ctypedefs()
|
||||
HandlesStruct.reset_visible_structs(mb, 0)
|
||||
|
||||
gen_tr.translate(gen_tree)
|
||||
|
||||
if gen_tr._global_names is not None:
|
||||
@@ -1199,6 +1201,19 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
HandlesType.clear_cdefine_constants()
|
||||
HandlesType.clear_ctypedefs()
|
||||
HandlesStruct.reset_visible_structs(mb, 0)
|
||||
|
||||
# 翻译前哨兵:AST 解析(lexer/tokenize/parse_tokens)同样在 pool 分配,
|
||||
# 若解析器越界写破坏了存活块 header,此处立即定位到当前文件
|
||||
# (崩溃点漂移排查:把"翻译过程中随机崩"变成确定性定位)
|
||||
pre_rc: t.CInt = mb.check_alive_blocks(mark1)
|
||||
if pre_rc != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(翻译前存活块, rc=%d): %s", pre_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
ret: int = tr.translate(tree)
|
||||
if ret != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
@@ -1286,7 +1301,34 @@ def RunPhase1(mb: memhub.MemBuddy | t.CPtr, includes_dir: str, temp_dir: str,
|
||||
# OOM 回收:回收本文件翻译产生的瞬时数据(AST/tokens/lexer/IR/Handler/dump 临时)
|
||||
# 持久表(struct/enum/REnum/spec 缓存/全局函数名等)已迁出 reset 区间(stdlib),
|
||||
# reset_to(mark1) 只回收 mark1 之后分配、未被单独 free 的块。
|
||||
#
|
||||
# 内存哨兵(崩溃点漂移排查):reset 前检查存活块 header(抓越界写),
|
||||
# reset 后检查 free list 完整性(抓链表损坏)。任一损坏立即终止,
|
||||
# 把"随机崩溃漂移"变成"确定性定位到当前文件"。
|
||||
# rc 语义(check_alive_blocks):1=块地址低于 usable,2=高于 usable+size,
|
||||
# 3=order 为负,4=order 超 max_order,5=块未对齐到 order 大小,
|
||||
# 6=块尾 canary 损坏(越界写穿数据区——事发地定位)
|
||||
# rc 语义(self_check):1/2=越界,3=对齐错,4=free list 成环/超步数
|
||||
chk_rc: t.CInt = mb.check_alive_blocks(mark1)
|
||||
if chk_rc != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(存活块 header, rc=%d): %s", chk_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
# A/B 实验结论(已确认):禁用 reset_to 后 stdarg 仍崩 → 越界写是根因,
|
||||
# 与回收/UAF 无关。恢复 reset_to,改用块尾 canary(check_alive_blocks 校验)
|
||||
# 定位越界写事发地到具体文件。
|
||||
mb.reset_to(mark1)
|
||||
sc_rc: t.CInt = mb.self_check()
|
||||
if sc_rc != 0:
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
viperlib.snprintf(fb, 1024,
|
||||
"内存损坏(free list, rc=%d): %s", sc_rc, file_path)
|
||||
VLogger.error(fb, "Phase1")
|
||||
stdlib.exit(1)
|
||||
|
||||
fb: t.CChar | t.CPtr = VLogger.fmt_buf()
|
||||
if fb is not None:
|
||||
|
||||
Reference in new issue
Block a user