diff --git a/App/lib/core/Gen/Call/CallGenCtor.vp b/App/lib/core/Gen/Call/CallGenCtor.vp index 693b651..0114fe7 100644 --- a/App/lib/core/Gen/Call/CallGenCtor.vp +++ b/App/lib/core/Gen/Call/CallGenCtor.vp @@ -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) diff --git a/App/lib/core/Gen/Class/ClassGenDef.vp b/App/lib/core/Gen/Class/ClassGenDef.vp index 7c24169..4897487 100644 --- a/App/lib/core/Gen/Class/ClassGenDef.vp +++ b/App/lib/core/Gen/Class/ClassGenDef.vp @@ -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, diff --git a/App/lib/core/Gen/Func/FuncGenBase.vp b/App/lib/core/Gen/Func/FuncGenBase.vp index 676c1e8..ad58987 100644 --- a/App/lib/core/Gen/Func/FuncGenBase.vp +++ b/App/lib/core/Gen/Func/FuncGenBase.vp @@ -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) diff --git a/App/lib/core/Gen/Func/FuncGenDef.vp b/App/lib/core/Gen/Func/FuncGenDef.vp index b1e97f8..60473e5 100644 --- a/App/lib/core/Gen/Func/FuncGenDef.vp +++ b/App/lib/core/Gen/Func/FuncGenDef.vp @@ -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) diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index 8735faf..2ec1f16 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -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)