From 6d3fc4569ca2d5a8654cd1a28e3074d537e6e2d0 Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 6 Aug 2026 19:50:46 +0800 Subject: [PATCH] =?UTF-8?q?=E9=80=9A=E8=BF=87=E4=BA=86=20Memhub=20BuddyTes?= =?UTF-8?q?t=20=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- App/lib/core/Handles/HandlesExpr.vp | 50 ++++++++++++++++++++++++- App/lib/core/Handles/HandlesExprCall.vp | 47 ++++++++++++++++++++++- 2 files changed, 95 insertions(+), 2 deletions(-) diff --git a/App/lib/core/Handles/HandlesExpr.vp b/App/lib/core/Handles/HandlesExpr.vp index 142b8d5..ced002c 100644 --- a/App/lib/core/Handles/HandlesExpr.vp +++ b/App/lib/core/Handles/HandlesExpr.vp @@ -1931,11 +1931,59 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr, # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 # (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 + # 注意:不能直接返回 Function 对象,也不能直接 build_bitcast(Function)—— + # Function 布局是 {Next, Name, RetTy, Params, ...},value_get_ty 会错位读到 + # Name 字段,TypePrint 输出 "void",生成 `bitcast void ... to i8*` 非法 IR; + # 且 Function.Next 是模块函数链表指针,参数链表构建对其赋值会截断函数链表, + # 最终打印出 `declare void @()` 空名函数。正确做法:按 Function 的 + # RetTy/Params 构造真实函数类型,用 new_value 包装成普通 Value 再 bitcast。 if trans is not None and trans.Module is not None: fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( trans.Module, nm_id) if fn_ref is not None: - return fn_ref + fn_name: t.CChar | t.CPtr = llvmlite.function_get_name(fn_ref) + if fn_name is None: + return None + # 构造函数类型:ret_ty + 参数 ParamNode 链表 + fn_ret_ty: llvmlite.LLVMType | t.CPtr = llvmlite.function_get_ret_ty(fn_ref) + if fn_ret_ty is None: + fn_ret_ty = llvmlite.Int32(pool) + fn_pp: llvmlite.Param | t.CPtr = llvmlite.function_get_param_head(fn_ref) + fn_first_node: llvmlite.ParamNode | t.CPtr = None + fn_prev_node: llvmlite.ParamNode | t.CPtr = None + fn_pcount: int = 0 + while fn_pp is not None: + fn_pty: llvmlite.LLVMType | t.CPtr = llvmlite.param_get_ty(fn_pp) + fn_pn: llvmlite.ParamNode | t.CPtr = llvmlite.new_param_node(pool, fn_pty) + if fn_pn is not None: + if fn_first_node is None: + fn_first_node = fn_pn + if fn_prev_node is not None: + llvmlite.paramnode_set_next(fn_prev_node, fn_pn) + fn_prev_node = fn_pn + fn_pcount += 1 + fn_pp = llvmlite.param_get_next(fn_pp) + fn_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Func( + pool, fn_ret_ty, fn_first_node, fn_pcount) + if fn_ty is None: + return None + # 构造函数指针 Value(new_value 包装,避免触碰 Function.Next) + fn_ref_v: llvmlite.Value | t.CPtr = llvmlite.new_value(pool) + if fn_ref_v is None: + return None + llvmlite.value_set_ty(fn_ref_v, llvmlite.Ptr(pool, fn_ty)) + llvmlite.value_set_isconst(fn_ref_v, 1) + fn_ref_name: t.CChar | t.CPtr = pool.alloc(256) + if fn_ref_name is not None: + fn_ref_name[0] = '\0' + if HandlesClassDef._vtable_name_needs_quote(fn_name) != 0: + viperlib.snprintf(fn_ref_name, 256, "@\"%s\"", fn_name) + else: + viperlib.snprintf(fn_ref_name, 256, "@%s", fn_name) + llvmlite.value_set_name(fn_ref_v, fn_ref_name) + fn_i8ptr_ty: llvmlite.LLVMType | t.CPtr = llvmlite.Ptr( + pool, llvmlite.Int8(pool)) + return llvmlite.build_bitcast(builder, fn_ref_v, fn_i8ptr_ty) # 所有查找路径均失败 # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错 diff --git a/App/lib/core/Handles/HandlesExprCall.vp b/App/lib/core/Handles/HandlesExprCall.vp index 7ede28e..74a1e2a 100644 --- a/App/lib/core/Handles/HandlesExprCall.vp +++ b/App/lib/core/Handles/HandlesExprCall.vp @@ -5182,6 +5182,11 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, # 查找函数:优先从函数表按裸名精确匹配(同模块函数), # 再从模块函数链表按后缀匹配(SHA1 前缀名)。 + # 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配—— + # "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被 + # 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data), + # 传入句柄数组等指针时把句柄值当地址写入直接崩溃。 + # 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。 # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) # 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 @@ -5190,7 +5195,47 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr, if actual_funcs is None and trans is not None: actual_funcs = trans._funcs actual_func_count = trans._func_count - found_func: llvmlite.Function | t.CPtr = find_func_in_module(mod, func_name) + found_func: llvmlite.Function | t.CPtr = None + if cl.func is not None and cl.func.kind() == ast.ASTKind.Name: + # 裸名调用:允许精确 + 后缀匹配 + found_func = find_func_in_module(mod, func_name) + else: + # 模块限定/属性调用:精确匹配优先,后缀匹配仅接受模块函数。 + # 后缀匹配命中的"方法"(SHA1.Class.method,Class 是已注册类)必须拒绝—— + # 短方法名(free/reset/close 等)会误命中其他模块的方法 + # (如 stdlib.free 命中 viperio.Buf.free,普通指针被当 Buf 释放崩溃; + # 且 atom.__atomic_test_and_set 若被误拒,返回类型从 i1 推断成 i32, + # 调用按 i32 读 i1 返回值读到垃圾高位,spinlock 恒非 0 卡死)。 + # 模块函数(SHA1.func)或子模块函数(SHA1.submod.func)的后缀匹配保留。 + found_func = find_func_in_module(mod, func_name) + if found_func is not None: + ff_name: t.CChar | t.CPtr = llvmlite.function_get_name(found_func) + if ff_name is not None: + ff_dots: int = 0 + ffi2: t.CSizeT = 0 + while ff_name[ffi2] != '\0': + if ff_name[ffi2] == '.': + ff_dots += 1 + ffi2 += 1 + if ff_dots >= 2: + # 提取第 2 段(SHA1.Class.method → Class;SHA1.submod.func → submod) + seg2: t.CChar | t.CPtr = pool.alloc(64) + if seg2 is not None: + seg2[0] = '\0' + si: t.CSizeT = 0 + while ff_name[si] != '\0' and si < 17: + si += 1 + seg_start: t.CSizeT = si + seg_end: t.CSizeT = si + while ff_name[seg_end] != '\0' and ff_name[seg_end] != '.': + seg_end += 1 + seg_len: t.CSizeT = seg_end - seg_start + if seg_len > 0 and seg_len < 63: + string.strncpy(seg2, ff_name + seg_start, seg_len) + seg2[seg_len] = '\0' + # 第 2 段是已注册结构体类 → 是方法,拒绝(走模块 SHA1 路径) + if HandlesStruct.get_struct_type(seg2) is not None: + found_func = None # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare # 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: