fix(tpv): 空类 FieldCount=0 中和重建 + 移除 [ATTR]/[DET] 调试打印
1) WIN32_FIND_DATAA 等空类(FieldCount=0)字段访问:模块限定路径补 FC==0 容忍(返回 None 交 pending,对齐裸名路径);ClassGenDef 空类不再 pending 延迟(多遍死锁),改为中和旧 entry 走完整注册重建。2) 用户要求移除 [ATTR](FuncGenBase/FuncGenDef)与 [DET](CallGenCtor)无条件调试打印。3) 拓宽 [DBG-REG]/[DBG-ADDF] 过滤器到 WIN32_FIND_DATAA 定位空类注册来源。
This commit is contained in:
1 parent
a99db2a29b
commit
b7eeb504ee
5 files changed
+28
-104
No files matched your search
@@ -119,49 +119,6 @@ class CallGenCtor(CallGenBase.CallGenBase):
|
||||
OOP 结构体:alloca → call __before_init__(ptr) → call __init__(ptr, args) 或 store 参数 → load
|
||||
普通结构体:alloca → zero + defaults → store 参数 → load
|
||||
"""
|
||||
# [DET] callee 入口 can 核对(无条件首条打印):与槽位悬空处 can 对比——
|
||||
# 入口即垃圾 = ABI 栈参数错位(caller 存/callee 读错位 4 字节);
|
||||
# 入口正常但槽位悬空处垃圾 = 函数内部 can 被改写(栈槽复用)。
|
||||
# 无条件打印仅在进入结构体构造时执行一次(每 ctor 一条,量可控)。
|
||||
stdio.printf("[DET] ctor入口: can=%llu cargs=%llu\n",
|
||||
t.CUInt64T(can), t.CUInt64T(cargs))
|
||||
# [DET] 读取侧存活校验(detection 模式启用):cargs(cl.args)必须指向
|
||||
# 存活块——不在记录表(或已 free)= use-after-free 读取(SlotsBugTest
|
||||
# KwEntry cargs 悬空根因定位)。is_alive 内部处理 detection==0 时不拦截,
|
||||
# 默认关闭无开销。补 _det_probe 写入侧检测的盲区。
|
||||
if cargs is not None and pool is not None:
|
||||
if pool.is_alive(cargs) == 0:
|
||||
# 打印 cargs 指向的块头:0=已 free(UAF 实锤) 奇数=活跃(记录表
|
||||
# 异常) 其它=非 pool 块(stdlib.malloc/垃圾指针)——定位悬空源
|
||||
blk_c: t.CUInt64T = t.CUInt64T(cargs) - 2 - 8
|
||||
hdr_c: t.CUInt64T = t.CUInt64T(c.Deref(t.CUInt64T(blk_c, t.CPtr)))
|
||||
stdio.printf("[DET] 读取悬空: struct-ctor cargs=%llu block=%llu hdr=0x%llX(0=free 奇数=活跃 其它=非pool块)\n",
|
||||
t.CUInt64T(cargs), blk_c, hdr_c)
|
||||
stdlib.exit(1)
|
||||
# [DET] 扩展:cargs 列表存活但槽位/数据可能未初始化或悬空(SlotsBugTest
|
||||
# ASAN 崩溃 node=0xCDCDCDCDCDCDCDCD——cargs.get(ai) 返回 0xCDCD 填充值:
|
||||
# 列表 __init__ 未执行(__data__/__count__=0xCDCD,MEMBUDDY_FILL_GUARD
|
||||
# 无条件填充)或 __data__ 悬空。列表头:__data__@0 __count__@8
|
||||
# __capacity__@16。命中 0xCDCD 即打印定位并 fail-fast。
|
||||
if cargs is not None:
|
||||
cd_fill: t.CUInt64T = (t.CUInt64T(0xCDCDCDCD) << 32) | t.CUInt64T(0xCDCDCDCD)
|
||||
lh_c: t.CUInt64T | t.CPtr = (t.CUInt64T | t.CPtr)(t.CVoid(cargs, t.CPtr))
|
||||
ldd_c: t.CUInt64T = lh_c[0]
|
||||
ldc_c: t.CUInt64T = lh_c[1]
|
||||
ldcap_c: t.CUInt64T = lh_c[2]
|
||||
if ldd_c == cd_fill or ldc_c == cd_fill:
|
||||
stdio.printf("[DET] 构造参数列表未初始化: cargs=%llu data=%llu count=%llu cap=%llu can=%llu\n",
|
||||
t.CUInt64T(cargs), ldd_c, ldc_c, ldcap_c, t.CUInt64T(can))
|
||||
stdlib.exit(1)
|
||||
ai_c: t.CSizeT = 0
|
||||
while ai_c < can:
|
||||
nd_c: ast.AST | t.CPtr = cargs.get(ai_c)
|
||||
if nd_c is not None and t.CUInt64T(nd_c) == cd_fill:
|
||||
stdio.printf("[DET] 构造参数槽位悬空: ai=%zu can=%llu node=%llu cargs=%llu data=%llu count=%llu cap=%llu\n",
|
||||
ai_c, t.CUInt64T(can), t.CUInt64T(nd_c), t.CUInt64T(cargs),
|
||||
ldd_c, ldc_c, ldcap_c)
|
||||
stdlib.exit(1)
|
||||
ai_c += 1
|
||||
# 创建临时 alloca
|
||||
# 确保跨模块结构体的完整定义在当前模块中可用(供 alloca 分配空间)
|
||||
self.Gen.StructGen.ensure_struct_def_in_module(pool, mod, struct_ty)
|
||||
|
||||
@@ -78,20 +78,22 @@ class ClassGenDef(ClassGenBase.ClassGenBase):
|
||||
# 检查是否已注册(用 SHA1 区分跨模块同名类)
|
||||
existing: GenTypes.StructEntry | t.CPtr = self.Gen.StructGen.find_struct_by_module(
|
||||
class_name, trans.ModuleSha1)
|
||||
# 空类注册不完整检测:existing FieldCount==0 但源类体声明了字段
|
||||
# (vpi 注入/注册缺陷,win32base SECURITY_ATTRIBUTES / win32file
|
||||
# WIN32_FIND_DATAA 根因)。此前标记 _deps_pending 延迟 → 空 entry 持久
|
||||
# 存在导致多遍死锁不收敛。改为中和旧 entry(置空 Name + Ty=None,使其
|
||||
# 不可再被 find_struct_by_module 命中),走下方完整注册路径重建。
|
||||
needs_rereg: int = 0
|
||||
if existing is not None:
|
||||
# BUG 5 方案1修改点2:existing 时字段完整性检查
|
||||
# 结构体已注册,但需验证字段信息是否完整(防止 i32 回退残留或注册不完整)
|
||||
# 注意:无字段类(接口/标记类,类体无 AnnAssign)合法(空 struct + 方法),
|
||||
# 仅当"类体声明了字段但 FieldCount==0"才算注册不完整(Phase A-pre 漏注册)。
|
||||
if existing.FieldCount == 0 and trans._declare_only == 0:
|
||||
if self.Gen.ClassGenBase._class_body_has_field(cd) != 0:
|
||||
# [DBG-EMP] 临时诊断:定位空类注册来源(win32base SECURITY_ATTRIBUTES)。
|
||||
# 报错期间改为 pending 延迟(不 fatal 中断多遍收敛),配合
|
||||
# register_struct/add_field 的 [DBG-EMP] 打印定位谁注册了空类。
|
||||
VLogger.info(f"[DBG-EMP] class={class_name} FC=0 ty={t.CUInt64T(existing.Ty)} 类体有字段", "DBG")
|
||||
if trans is not None:
|
||||
trans._deps_pending = 1
|
||||
return 0
|
||||
VLogger.info(f"[DBG-EMP] class={class_name} FC=0 ty={t.CUInt64T(existing.Ty)} 类体有字段,中和重建", "DBG")
|
||||
if existing.Name is not None:
|
||||
existing.Name[0] = '\0'
|
||||
existing.Ty = None
|
||||
existing.FieldCount = 0
|
||||
needs_rereg = 1
|
||||
if existing is not None and needs_rereg == 0:
|
||||
# 结构体已注册(Phase A-pre 多遍扫描或 Phase B 重新翻译),但仍需在当前模块中翻译方法
|
||||
if existing.Ty is not None:
|
||||
# Phase 1b(declare_only=0):existing.Ty 是 Phase 1a 注册的 struct_ty,
|
||||
|
||||
@@ -46,100 +46,58 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
attrs_buf[0] = '\0'
|
||||
found_any: int = 0
|
||||
|
||||
# [ATTR-DIAG] 运行时诊断:定位 @c.Attribute 属性为何未进入 IR(stackrealign)
|
||||
cur_file: str = self.Gen.TypeGenResolve.get_current_file()
|
||||
if cur_file is None:
|
||||
cur_file = "?"
|
||||
|
||||
for di in range(dn):
|
||||
deco: ast.AST | t.CPtr = decorator_list.get(di)
|
||||
if deco is None:
|
||||
stdio.printf("[ATTR] deco[%d]=None\n", di)
|
||||
continue
|
||||
dk: int = deco.kind()
|
||||
stdio.printf("[ATTR] deco[%d] kind=%d\n", di, dk)
|
||||
if dk != ast.ASTKind.Call:
|
||||
continue
|
||||
call_node: ast.Call | t.CPtr = (ast.Call | t.CPtr)(deco)
|
||||
if call_node.func is None:
|
||||
stdio.printf("[ATTR] call.func=None\n")
|
||||
continue
|
||||
cfk: int = call_node.func.kind()
|
||||
stdio.printf("[ATTR] call.func kind=%d\n", cfk)
|
||||
if cfk != ast.ASTKind.Attribute:
|
||||
continue
|
||||
|
||||
# 检测 c.Attribute
|
||||
func_attr: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(call_node.func)
|
||||
if func_attr.attr is None:
|
||||
stdio.printf("[ATTR] func_attr.attr=None\n")
|
||||
continue
|
||||
stdio.printf("[ATTR] func_attr.attr='%s'\n", func_attr.attr)
|
||||
if string.strcmp(func_attr.attr, "Attribute") != 0:
|
||||
continue
|
||||
if func_attr.value is None:
|
||||
stdio.printf("[ATTR] func_attr.value=None\n")
|
||||
continue
|
||||
fvk: int = func_attr.value.kind()
|
||||
stdio.printf("[ATTR] func_attr.value kind=%d\n", fvk)
|
||||
if fvk != ast.ASTKind.Name:
|
||||
continue
|
||||
c_name: ast.Name | t.CPtr = (ast.Name | t.CPtr)(func_attr.value)
|
||||
if c_name.id is None:
|
||||
stdio.printf("[ATTR] c_name.id=None\n")
|
||||
continue
|
||||
stdio.printf("[ATTR] c_name.id='%s'\n", c_name.id)
|
||||
if string.strcmp(c_name.id, "c") != 0:
|
||||
continue
|
||||
imp_c: int = self.Gen.ImportsGen.is_module_imported(imported_modules, "c")
|
||||
stdio.printf("[ATTR] is_module_imported('c')=%d\n", imp_c)
|
||||
if imp_c == 0:
|
||||
continue
|
||||
|
||||
# 遍历参数提取属性
|
||||
if call_node.args is None:
|
||||
stdio.printf("[ATTR] call.args=None\n")
|
||||
continue
|
||||
dbuf: bytes = pool.alloc(1024)
|
||||
if dbuf is not None:
|
||||
dbuf[0] = '\0'
|
||||
dpos: t.CSizeT = deco.dump(dbuf, 1024, 0)
|
||||
if dpos < 1024:
|
||||
dbuf[dpos] = '\0'
|
||||
stdio.printf("[ATTR] deco.dump='%s'\n", dbuf)
|
||||
args_list: list[ast.AST | t.CPtr] | t.CPtr = call_node.args
|
||||
an: t.CSizeT = len(args_list)
|
||||
stdio.printf("[ATTR] args_len=%d\n", an)
|
||||
if call_node.keywords is not None:
|
||||
kwl: t.CSizeT = len(call_node.keywords)
|
||||
stdio.printf("[ATTR] keywords_len=%d\n", kwl)
|
||||
for kwi in range(kwl):
|
||||
kwnd: ast.AST | t.CPtr = call_node.keywords.get(kwi)
|
||||
if kwnd is not None:
|
||||
stdio.printf("[ATTR] kw[%d] kind=%d\n", kwi, kwnd.kind())
|
||||
for ai in range(an):
|
||||
arg_node: ast.AST | t.CPtr = args_list.get(ai)
|
||||
if arg_node is None:
|
||||
stdio.printf("[ATTR] arg[%d]=None\n", ai)
|
||||
continue
|
||||
stdio.printf("[ATTR] arg[%d] kind=%d\n", ai, arg_node.kind())
|
||||
|
||||
# 提取属性名(t.attr.xxx / t.attr.xxx() / t.attr.llvm.xxx)
|
||||
attr_name: str = self._get_attr_name_from_node(arg_node)
|
||||
if attr_name is None:
|
||||
stdio.printf("[ATTR] arg[%d] name=None\n", ai)
|
||||
continue
|
||||
|
||||
# 映射到 LLVM 属性名并追加
|
||||
ar: int = self._append_llvm_attr(attrs_buf, attr_name)
|
||||
stdio.printf("[ATTR] arg[%d] name='%s' append=%d buf='%s' blen=%zu b0=0x%02x\n",
|
||||
ai, attr_name, ar, attrs_buf, string.strlen(attrs_buf), attrs_buf[0])
|
||||
if ar != 0:
|
||||
found_any = 1
|
||||
# 追加成功后,如果不是最后一个属性,添加空格分隔
|
||||
# 在下一次追加前由 _append_str 处理
|
||||
|
||||
stdio.printf("[ATTR] found_any=%d return='%s'\n", found_any, attrs_buf)
|
||||
if found_any == 0:
|
||||
return None
|
||||
return attrs_buf
|
||||
@@ -226,7 +184,6 @@ class FuncGenBase(CallGenBase.CallGenBase):
|
||||
max_len = 256
|
||||
cur_len: t.CSizeT = string.strlen(buf)
|
||||
s_len: t.CSizeT = string.strlen(s)
|
||||
stdio.printf("[ATTR] _append_str: max_len=%zu cur=%zu slen=%zu s='%s'\n", max_len, cur_len, s_len, s)
|
||||
if cur_len + s_len + 1 > max_len:
|
||||
return # 无剩余容量:丢弃本次追加,避免越界写
|
||||
string.strcpy(buf + cur_len, s)
|
||||
|
||||
@@ -467,7 +467,6 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
llvmlite.add_param(pool, func, param_ty_e, pname_e)
|
||||
|
||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||
stdio.printf("[ATTR] call@decl: func='%s'\n", fd.name)
|
||||
func_attrs_e: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs_e is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs_e)
|
||||
@@ -486,7 +485,6 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
# 复用前向声明:清除 IsDeclared 标记,转为 define
|
||||
func.IsDeclared = 0
|
||||
# 装饰器属性设置(前向声明时未设置)
|
||||
stdio.printf("[ATTR] call@reuse: func='%s' mod_sha1='%s'\n", fd.name, trans.ModuleSha1)
|
||||
func_attrs_reuse: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs_reuse is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs_reuse)
|
||||
@@ -498,7 +496,6 @@ class FuncGenDef(CallGenBase.CallGenBase):
|
||||
return 0
|
||||
|
||||
# 提取 @c.Attribute 装饰器属性并设置到函数
|
||||
stdio.printf("[ATTR] call@new: func='%s'\n", fd.name)
|
||||
func_attrs: str = self.Gen.FuncGenBase.extract_func_attrs(pool, fd.decorator_list, imported_modules)
|
||||
if func_attrs is not None:
|
||||
llvmlite.function_set_attrs(func, func_attrs)
|
||||
|
||||
@@ -221,8 +221,10 @@ class StructGenMixin:
|
||||
|
||||
entry.Ty = struct_ty
|
||||
entry.FieldCount = 0
|
||||
# [DBG-EMP] 临时诊断:定位空类注册来源(win32base SECURITY_ATTRIBUTES)
|
||||
if name is not None and string.strstr(name, "SECURITY_ATTRIBUTES") is not None:
|
||||
# [DBG-EMP] 临时诊断:定位空类注册来源(win32base SECURITY_ATTRIBUTES /
|
||||
# win32file WIN32_FIND_DATAA FieldCount=0)
|
||||
if name is not None and (string.strstr(name, "SECURITY_ATTRIBUTES") is not None
|
||||
or string.strstr(name, "WIN32_FIND_DATAA") is not None):
|
||||
sha1_s: str = "?"
|
||||
if sha1 is not None:
|
||||
sha1_s = sha1
|
||||
@@ -357,8 +359,10 @@ class StructGenMixin:
|
||||
return -1
|
||||
|
||||
idx: int = struct_entry.FieldCount
|
||||
# [DBG-EMP] 临时诊断:定位空类字段添加(win32base SECURITY_ATTRIBUTES)
|
||||
if struct_entry.Name is not None and string.strstr(struct_entry.Name, "SECURITY_ATTRIBUTES") is not None:
|
||||
# [DBG-EMP] 临时诊断:定位空类字段添加(win32base SECURITY_ATTRIBUTES /
|
||||
# win32file WIN32_FIND_DATAA FieldCount=0)
|
||||
if struct_entry.Name is not None and (string.strstr(struct_entry.Name, "SECURITY_ATTRIBUTES") is not None
|
||||
or string.strstr(struct_entry.Name, "WIN32_FIND_DATAA") is not None):
|
||||
VLogger.info(f"[DBG-ADDF] {struct_entry.Name} field={field_name} idx={idx}", "DBG")
|
||||
fe: GenTypes.FieldEntry | t.CPtr = self._get_field_entry(struct_entry, idx)
|
||||
if fe is None:
|
||||
@@ -878,6 +882,13 @@ class StructGenMixin:
|
||||
mod_entry_q: GenTypes.StructEntry | t.CPtr = \
|
||||
self.find_struct_by_module(bare_q, mod_sha1_q)
|
||||
if mod_entry_q is not None:
|
||||
# 依赖未就绪容忍(对齐裸名路径 L926):FieldCount==0 的
|
||||
# 空类(注册不完整/源模块未编译)→ 返回 None 让上层标记
|
||||
# _deps_pending 下遍重译,不在此 fatal(WIN32_FIND_DATAA
|
||||
# 字段访问 cFileName 报 FieldCount=0 根因之一)。
|
||||
if mod_entry_q.FieldCount == 0:
|
||||
stdlib.free(mod_buf_q)
|
||||
return None
|
||||
for fi_q in range(mod_entry_q.FieldCount):
|
||||
fe_q: GenTypes.FieldEntry | t.CPtr = \
|
||||
self._get_field_entry(mod_entry_q, fi_q)
|
||||
|
||||
Reference in new issue
Block a user