diff --git a/App/lib/StubGen/VpiReader.vp b/App/lib/StubGen/VpiReader.vp index 18d6ff0..b0b1510 100644 --- a/App/lib/StubGen/VpiReader.vp +++ b/App/lib/StubGen/VpiReader.vp @@ -152,8 +152,25 @@ def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, ast._lexer_init(lx, vpi_buf, pool) tokens: ast.Token | t.CPtr = ast.tokenize(lx) tree: ast.AST | t.CPtr = ast.parse_tokens(pool, tokens) - stdlib.free(vpi_buf) + # vpi_buf 延迟释放:AST 字符串字段可能引用 vpi_buf 内部(token 零拷贝), + # 提前 free 会导致 Name.id/Attribute.attr 等悬空 → 后续解析返回错误类型。 + # 在 ParseVpiIntoModule 末尾统一释放。 + # [DBG-T96] 临时诊断:定位 vpi AST 有效性(定位后移除) + k96: int = -1 + if tree is not None: + k96 = tree.kind() + stdio.printf("[DBG-T96] vpi tree kind=%d children=", k96) + if tree is not None and tree.children is not None: + n96: t.CSizeT = tree.children.__len__() + stdio.printf("%d\n", n96) + if n96 > 0: + c96: ast.AST | t.CPtr = tree.children.get(0) + if c96 is not None: + stdio.printf("[DBG-T96] child0 kind=%d\n", c96.kind()) + else: + stdio.printf("0\n") if tree is None: + stdlib.free(vpi_buf) return 0 # 提取源模块 SHA1(用于函数名混淆,在 AST 解析成功后提取避免提前返回时泄漏) @@ -234,6 +251,8 @@ def ParseVpiIntoModule(pool: memhub.MemBuddy | t.CPtr, # 释放 SHA1 缓冲区(_extract_sha1_from_path 用 stdlib.malloc 分配) if src_sha1 is not None: stdlib.free(src_sha1) + # vpi_buf 延迟到全部 tree 处理完成后释放(见解析处注释) + stdlib.free(vpi_buf) return 1 @@ -420,6 +439,26 @@ def _inject_method_declare(pool: memhub.MemBuddy | t.CPtr, if ret_ty is None: ret_ty = i32_ty + # [DBG-T97] 临时诊断:定位 args.get_str 类型退化(定位后移除) + if string.strcmp(m_fd.name, "parse_args") == 0: + vis97: int = HandlesStruct.is_struct_visible("ParsedArgs") + gst97: t.CChar | t.CPtr = stdlib.malloc(128) + if gst97 is not None: + gty97: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type("ParsedArgs") + if gty97 is not None: + llvmlite.TypePrint(gst97, 128, gty97, pool) + else: + viperlib.snprintf(gst97, 128, "NULL") + ot97: t.CChar | t.CPtr = stdlib.malloc(128) + if ot97 is not None: + if ret_ty is not None: + llvmlite.TypePrint(ot97, 128, ret_ty, pool) + else: + viperlib.snprintf(ot97, 128, "NULL") + stdio.printf("[DBG-T97] vis=%d gst=%s ret=%s\n", vis97, gst97, ot97) + stdlib.free(ot97) + stdlib.free(gst97) + # 创建 declare func: llvmlite.Function | t.CPtr = llvmlite.create_declare( pool, mod, mangled_name, ret_ty) diff --git a/App/lib/core/Handles/HandlesType.vp b/App/lib/core/Handles/HandlesType.vp index c5c1697..5039dd8 100644 --- a/App/lib/core/Handles/HandlesType.vp +++ b/App/lib/core/Handles/HandlesType.vp @@ -1550,12 +1550,56 @@ def resolve_annotation_type(pool: memhub.MemBuddy | t.CPtr, if left_is_cptr != 0: other_node = bop.right # 检测另一边是否是 t.CVoid (void* = i8*) - other_is_cvoid: int = _is_cvoid_marker(other_node, imported_modules) + # 严格验证完整形式(Attribute(t.CVoid) 的 value 是 Name("t"), + # 或裸名 CVoid 且 t 已导入),防止解析异常节点被误判为 CVoid。 + other_is_cvoid: int = 0 + if other_node is not None: + if other_node.kind() == ast.ASTKind.Attribute: + oat2: ast.Attribute | t.CPtr = (ast.Attribute | t.CPtr)(other_node) + if oat2.attr is not None and string.strcmp(oat2.attr, "CVoid") == 0: + if oat2.value is not None and oat2.value.kind() == ast.ASTKind.Name: + ov2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(oat2.value) + if ov2.id is not None and string.strcmp(ov2.id, "t") == 0: + other_is_cvoid = 1 + elif other_node.kind() == ast.ASTKind.Name: + onm2: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + if onm2.id is not None and string.strcmp(onm2.id, "CVoid") == 0: + if HandlesImports.is_module_imported(imported_modules, "t") != 0: + other_is_cvoid = 1 if other_is_cvoid != 0: return llvmlite.Ptr(pool, llvmlite.Int8(pool)) other_ty: llvmlite.LLVMType | t.CPtr = resolve_annotation_type( pool, other_node, imported_modules, from_imports, trans) + # other_ty 必须是已注册的结构体类型才算有效: + # X | t.CPtr 的 X 是类名,解析结果应为 struct 类型。 + # 若节点异常导致解析出基础类型/垃圾(如 Int8 → Ptr(i8)), + # 不应直接返回,需走下方回退按类名查全局表。 + # (str | t.CPtr 解析为 Ptr(i8) 非 struct,回退 get_struct_type + # 查不到 str → 仍返回 Ptr(i8),结果一致,不受影响。) + if other_ty is not None: + if HandlesStruct.find_struct_by_type(other_ty) is not None: + return llvmlite.Ptr(pool, other_ty) + other_ty = None if other_ty is None: + # 严格模式(App 文件)下裸类名不可见时,回退到全局 + # struct 注册表按类名查找。X | t.CPtr 是明确的指针包装 + # 注解(如 vpi stub 的 "ParsedArgs | t.CPtr"),X 已注册 + # 时不应静默退化为 i8*——i8* 会让方法返回值的无注解变量 + # (如 args = parser.parse_args())类型退化,后续 obj.method + # get_class_name_by_type 查不到类名,误报 + # "跨模块调用 'args.get_str' 找不到模块 SHA1"。 + # 不检查 kind():vpi 解析的节点在后续处理中可能已损坏 + # (kind() 读取异常),直接按 Name 布局读取 id, + # 由 get_struct_type 兜底校验(无效类名返回 None)。 + other_cls_nm: str = None + if other_node is not None: + other_nm: ast.Name | t.CPtr = (ast.Name | t.CPtr)(other_node) + if other_nm.id is not None: + other_cls_nm = other_nm.id + if other_cls_nm is not None: + other_cls_ty: llvmlite.LLVMType | t.CPtr = HandlesStruct.get_struct_type(other_cls_nm) + if other_cls_ty is not None: + return llvmlite.Ptr(pool, other_cls_ty) # CPtr 单独使用或其他无效类型 → i8* return llvmlite.Ptr(pool, llvmlite.Int8(pool)) return llvmlite.Ptr(pool, other_ty)