通过了 Memhub BuddyTest 测试

This commit is contained in:
TermiNexus committed 2026-08-06 19:50:46 +08:00
1 parent f8436c74d2
commit 6d3fc4569c
2 files changed
+95 -2

No files matched your search

+49 -1
View File
@@ -1931,11 +1931,59 @@ def translate_name_value(builder: llvmlite.IRBuilder | t.CPtr,
# 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。 # 模块级函数引用:函数名作为值传递(如 CreateThread(..., _thread_alloc_free, ...))。
# 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移 # 之前缺失此查找导致函数名参数翻译返回 None 被跳过,后续参数整体前移
# (lpStartAddress 变成对象地址,线程从数据区执行直接崩溃)。 # (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: if trans is not None and trans.Module is not None:
fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module( fn_ref: llvmlite.Function | t.CPtr = HandlesExprCall.find_func_in_module(
trans.Module, nm_id) trans.Module, nm_id)
if fn_ref is not None: 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)的名字报错 # fail-fast: 仅对符合 CDefine 命名约定(ALL_CAPS)的名字报错
+46 -1
View File
@@ -5182,6 +5182,11 @@ def translate_call(pool: memhub.MemBuddy | t.CPtr,
# 查找函数:优先从函数表按裸名精确匹配(同模块函数), # 查找函数:优先从函数表按裸名精确匹配(同模块函数),
# 再从模块函数链表按后缀匹配(SHA1 前缀名)。 # 再从模块函数链表按后缀匹配(SHA1 前缀名)。
# 注意:模块限定/属性调用(如 stdlib.free)不能做后缀匹配——
# "free" 会误命中 viperio.Buf.free 等方法,导致普通 malloc 指针被
# 当作 Buf 对象释放(Buf.free 读 self 字段/写 self.data),
# 传入句柄数组等指针时把句柄值当地址写入直接崩溃。
# 后缀匹配仅用于裸名调用(cl.func 是 Name,如 _thread_alloc_free)。
# stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None, # stubs 在翻译后才注入,翻译时跨模块函数 found_func 通常为 None,
# 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*) # 此时根据函数名推断 includes 库函数的返回类型(如 strchr 返回 i8*)
# 如果调用方未传 funcs_ptr/func_count(如 AnnAssign 路径),从 trans 获取 # 如果调用方未传 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: if actual_funcs is None and trans is not None:
actual_funcs = trans._funcs actual_funcs = trans._funcs
actual_func_count = trans._func_count 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 # C 库函数裸名调用支持:若模块中找不到且是已知 C 库函数,自动创建 declare
# 对应 TPC 的 _C_LIB_FUNCS 机制,支持 memset/memmove/memcmp/strcmp 等裸名调用 # 对应 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: if found_func is None and cl.func is not None and cl.func.kind() == ast.ASTKind.Name: