diff --git a/App/lib/core/Gen/Call/CallGenCBuiltin.vp b/App/lib/core/Gen/Call/CallGenCBuiltin.vp index 28ada66..0c2cdee 100644 --- a/App/lib/core/Gen/Call/CallGenCBuiltin.vp +++ b/App/lib/core/Gen/Call/CallGenCBuiltin.vp @@ -1017,10 +1017,12 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): def _asm_name_is_mangled(self, name: str) -> int: - """判断 LLVM 名称是否带 SHA1 混淆头(16 hex + '.'),返回 1=是 + """判断 LLVM 名称是否带 SHA1 混淆头("{16位小写hex}."),返回 1=是 兼容 make_global_ref 生成的 '@"sha1.name"' 引用名和 GlobalVariable 裸名 "sha1.name"。'@name' 裸引用与局部 SSA(%N)都不算混淆。 + 判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛:不再接受大写 hex, + 也不再扫描任意位置的 '.' 后回看 16 字节,避免 "a.b..." 形态误判)。 """ if name is None: return 0 @@ -1029,22 +1031,10 @@ class CallGenCBuiltin(CallGenBase.CallGenBase): # 去掉 '@"..."' 包装(引用名) if nlen >= 3 and n[0] == '@' and n[1] == '"' and n[nlen - 1] == '"': n = n + 2 - nlen -= 3 elif nlen >= 1 and n[0] == '@': n = n + 1 - nlen -= 1 - if nlen <= 17: - return 0 - for i in range(16, nlen): - if n[i] == '.': - ok: int = 1 - for j in range(16): - cc: char = n[i - 16 + j] - if not (('0' <= cc <= '9') or ('a' <= cc <= 'f') or ('A' <= cc <= 'F')): - ok = 0 - break - if ok != 0: - return 1 + if GenApi.sha1_prefix_len(n) != 0: + return 1 return 0 diff --git a/App/lib/core/Gen/Call/CallGenCall.vp b/App/lib/core/Gen/Call/CallGenCall.vp index d4c43de..a69265e 100644 --- a/App/lib/core/Gen/Call/CallGenCall.vp +++ b/App/lib/core/Gen/Call/CallGenCall.vp @@ -714,11 +714,12 @@ class CallGenCall(CallGenBase.CallGenBase): # 保证 get/append 等 list 内置方法一律命中、绝不进入 MRO 解析。 if method_name is not None and class_name is not None: lb_cls: str = class_name - # 剥离跨模块特化名 sha1 前缀 "{16hex}."({sha}.list[...] 形态) - if string.strncmp(lb_cls, "list", 4) != 0 \ - and string.strlen(lb_cls) > 17 and lb_cls[16] == '.': - if string.strncmp(lb_cls + 17, "list", 4) == 0: - lb_cls = lb_cls + 17 + # 剥离跨模块特化名 sha1 前缀 "{16hex}."({sha}.list[...] 形态); + # 前缀长度判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛)。 + lb_pfx_d: int = GenApi.sha1_prefix_len(lb_cls) + if string.strncmp(lb_cls, "list", 4) != 0 and lb_pfx_d != 0: + if string.strncmp(lb_cls + lb_pfx_d, "list", 4) == 0: + lb_cls = lb_cls + lb_pfx_d if self.Gen.CallGenProp._is_list_builtin_method(lb_cls, method_name) != 0: # 双指针槽形态(rowptr[list[...]] 局部变量 alloca Ptr(Ptr(Struct)) # 直接传入时先 load 一层得到对象指针 Ptr(Struct),与分派方 @@ -903,8 +904,10 @@ class CallGenCall(CallGenBase.CallGenBase): match mc_struct_ty: case llvmlite.LLVMType.Struct(_fs_sp, _fc_sp, type_name_sp): if type_name_sp is not None and type_name_sp[0] != '\0': - tl_sp: sizet = string.strlen(type_name_sp) - if tl_sp >= 16: + # 仅当类型名确为 "{16hex}.{Class}" 才提取 sha1; + # 判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛), + # 避免把裸类名前 16 字节误当 sha1。 + if GenApi.sha1_prefix_len(type_name_sp) != 0: sb_sp: str = pool.alloc(17) if sb_sp is not None: string.strncpy(sb_sp, type_name_sp, 16) @@ -1186,8 +1189,9 @@ class CallGenCall(CallGenBase.CallGenBase): match mc_struct_ty: case llvmlite.LLVMType.Struct(_fields_st, _fcount_st, type_name_st): if type_name_st is not None and type_name_st[0] != '\0': - type_len_st: sizet = string.strlen(type_name_st) - if type_len_st >= 16: + # 仅当类型名确为 "{16hex}.{Class}" 才提取 sha1; + # 判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛)。 + if GenApi.sha1_prefix_len(type_name_st) != 0: sha1_from_ty: str = pool.alloc(17) if sha1_from_ty is not None: string.strncpy(sha1_from_ty, type_name_st, 16) @@ -1203,8 +1207,9 @@ class CallGenCall(CallGenBase.CallGenBase): viperlib.snprintf(mangled_anc, ml_anc, "%s.%s.%s", ret_anc_sha1, ret_anc_name, method_name) call_name = mangled_anc - # 类型名提取的 sha1 无法保证为真实模块 sha1(跨模块 stub 类型名 - # 带前缀但 find_struct 未注册时仍可用),此处不校验格式 + # 类型名提取的 sha1 已按 "{16hex}." 前缀格式校验(sha1_prefix_len); + # 不校验它是否为真实已注册模块 sha1(跨模块 stub 类型名带前缀但 + # find_struct 未注册时仍可用) elif ret_anc_name is not None and ret_anc_sha1 is None: # fail-fast:方法所属类既查不到 SHA1 又从类型名提取失败, # 禁止静默裸名(否则链接期 undefined symbol 难以定位) diff --git a/App/lib/core/Gen/Call/CallGenFd.vp b/App/lib/core/Gen/Call/CallGenFd.vp index 2f5bd14..29980e8 100644 --- a/App/lib/core/Gen/Call/CallGenFd.vp +++ b/App/lib/core/Gen/Call/CallGenFd.vp @@ -7,6 +7,7 @@ import memhub import string import viperlib import lib.core.Gen.Translator as HT +import lib.core.Gen.GenApi as GenApi from . import CallGenBase @@ -176,14 +177,17 @@ class CallGenFd(CallGenBase.CallGenBase): # 为 Ptr(i8),调用方变量 alloca 类型随之退化 → parts[0] 走字符下标 # 路径而非 list 内联 __getitem__(printf %s 解引用字符值崩溃)。 # 从定义模块 text.ll 读取精确返回类型(对齐普通方法调用 _translate_method_call)。 - fd_sha1: str = pool.alloc(17) - if fd_sha1 is not None: - string.strncpy(fd_sha1, fd_fname, 16) - fd_sha1[16] = '\0' - fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( - pool, fd_sha1, fd_cls, method_name) - if fd_exact is not None: - fd_ret_ty = fd_exact + # 仅当函数名确为 "{16hex}.{func}" 才提取模块 sha1(判定走唯一真源 + # GenApi.sha1_prefix_len,C10 收敛),避免把裸名前 16 字节误当 sha1。 + if GenApi.sha1_prefix_len(fd_fname) != 0: + fd_sha1: str = pool.alloc(17) + if fd_sha1 is not None: + string.strncpy(fd_sha1, fd_fname, 16) + fd_sha1[16] = '\0' + fd_exact: llvmlite.LLVMType | t.CPtr = self._LookupMethodRetTyFromTextLL( + pool, fd_sha1, fd_cls, method_name) + if fd_exact is not None: + fd_ret_ty = fd_exact fd_total: int = 1 + fd_can return llvmlite.build_call(builder, fd_fname, fd_head, fd_total, fd_ret_ty, 0) # ============================================================ diff --git a/App/lib/core/Gen/Call/CallGenLib.vp b/App/lib/core/Gen/Call/CallGenLib.vp index 62a2378..bc70ac8 100644 --- a/App/lib/core/Gen/Call/CallGenLib.vp +++ b/App/lib/core/Gen/Call/CallGenLib.vp @@ -7,6 +7,7 @@ import string import stdlib import lib.core.Gen.Translator as HT import lib.Stub.StubGen.VpiReader as VpiReader +import lib.core.Gen.GenApi as GenApi from . import CallGenBase @@ -636,26 +637,17 @@ class CallGenLib(CallGenBase.CallGenBase): return None def _is_sha1_mangled_call(self, call_name: str) -> int: - """判断 call_name 是否为跨模块 Viper 函数("{16位hex}.func" 形式) + """判断 call_name 是否为跨模块 Viper 函数("{16位小写hex}.func" 形式) C 库函数(strlen 等裸名)和 Win32 API(VirtualAlloc 等裸名)返回 0, 不参与精确返回类型解析(走 _infer_external_func_ret_ty 白名单)。 + 判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛:不再接受大写 hex)。 """ if call_name is None: return 0 - first_dot: str = string.strchr(call_name, '.') - if first_dot is None: - return 0 - pre_len: sizet = sizet(uint64(first_dot) - uint64(call_name)) - if pre_len != 16: - return 0 - for hx in range(16): - ch: int = call_name[hx] - if ch < 48 or ch > 57: - if ch < 97 or ch > 102: - if ch < 65 or ch > 70: - return 0 - return 1 + if GenApi.sha1_prefix_len(call_name) != 0: + return 1 + return 0 def _emit_llvm_memcpy_intrinsic(self, pool: rowptr[memhub.MemBuddy], builder: llvmlite.IRBuilder | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr, diff --git a/App/lib/core/Gen/Call/CallGenMixin.vp b/App/lib/core/Gen/Call/CallGenMixin.vp index 6a468ca..cec3304 100644 --- a/App/lib/core/Gen/Call/CallGenMixin.vp +++ b/App/lib/core/Gen/Call/CallGenMixin.vp @@ -1254,16 +1254,15 @@ class CallGenMixin(CallGenBase.CallGenBase): # (该分支仅 found_func None 的模块限定路径),这里对带前缀 # 的 declare 提取 sha1 再查 CExport 注册表,命中则改用裸名。 if found_func.IsDeclared != 0: - dot_pos_cx: str = string.strchr(found_name, 46) - if dot_pos_cx is not None: - cx_pre_len: sizet = string.strlen(found_name) - string.strlen(dot_pos_cx) - if cx_pre_len == 16: - cx_sha1_buf: str = pool.alloc(17) - if cx_sha1_buf is not None: - string.memcpy(cx_sha1_buf, found_name, 16) - cx_sha1_buf[16] = '\0' - if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0: - call_name = func_name + # 判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛:此前只判 + # 首个 '.' 前恰 16 字节、不校验 hex 形态)。 + if GenApi.sha1_prefix_len(found_name) != 0: + cx_sha1_buf: str = pool.alloc(17) + if cx_sha1_buf is not None: + string.memcpy(cx_sha1_buf, found_name, 16) + cx_sha1_buf[16] = '\0' + if self.Gen.CallGenBase.is_cexport_func(cx_sha1_buf, func_name) != 0: + call_name = func_name else: # 跨模块函数调用:found_func 为 None 时,检查是否是模块限定调用 # 如 string.strchr(...) → @{sha1_of_string}.strchr diff --git a/App/lib/core/Gen/StructGenMixin.vp b/App/lib/core/Gen/StructGenMixin.vp index 1115d4d..b34214d 100644 --- a/App/lib/core/Gen/StructGenMixin.vp +++ b/App/lib/core/Gen/StructGenMixin.vp @@ -14,6 +14,7 @@ import lib.Stub.StubMerger.StubMergerStore as StubMergerStore import lib.core.Gen.GenTypes as GenTypes import lib.core.Gen.Generator as Generator import lib.core.Gen.Type.TypeSpec as TSpec +import lib.core.Gen.GenApi as GenApi # ============================================================ # StructGenMixin - 结构体注册/字段查找 Mixin(对象化 P2-2,wiki/14-oo-refactor.md) @@ -797,13 +798,11 @@ class StructGenMixin: # "Thread") 命中 vthreading 的 entry → 其 arg@3 被当成 # sched.Thread.arg(应 4)→ th.func 被 th.arg=None 覆盖 → # _thread_entry call 0 → #UD/#GP)。strncmp 不分配临时缓冲。 + # 前缀判定走唯一真源 GenApi.sha1_prefix_len(C10 收敛:此前只判 + # 首个 '.' 前恰 16 字节、不校验 hex 形态)。 ty_has_sha1_lf: int = 0 - dot_ty_lf: str = string.strchr(ty_name, '.') - if dot_ty_lf is not None: - pre_len_lf: sizet = sizet( - uint64(dot_ty_lf) - uint64(ty_name)) - if pre_len_lf == 16: - ty_has_sha1_lf = 1 + if GenApi.sha1_prefix_len(ty_name) != 0: + ty_has_sha1_lf = 1 for i in range(self.StructCount): entry: GenTypes.StructEntry | t.CPtr = self._get_struct_entry(i) if entry is not None and entry.Name is not None: diff --git a/App/lib/core/Gen/Type/TypeGenResolve.vp b/App/lib/core/Gen/Type/TypeGenResolve.vp index ac3977e..33f4d20 100644 --- a/App/lib/core/Gen/Type/TypeGenResolve.vp +++ b/App/lib/core/Gen/Type/TypeGenResolve.vp @@ -2144,7 +2144,9 @@ class TypeGenResolve(TypeGenBase.TypeGenBase): # SHA1 前缀形态优先用完整名 "{sha1}.{Class}" 精确命中定义侧 # struct(get_struct_type 类名回退可能命中跨模块同名类) full_attr_ty: llvmlite.LLVMType | t.CPtr = None - if is_builtin_attr == 0 and string.strlen(val_name.id) == 16: + # val_name.id 是模块名段:恰为 16 位小写 hex 才是 SHA1 别名 + #(判定走唯一真源 GenApi.is_sha1_hex16,C10 收敛)。 + if is_builtin_attr == 0 and GenApi.is_sha1_hex16(val_name.id) != 0: full_q: str = self._concat_sha1_class(pool, val_name.id, at.attr) if full_q is not None: full_attr_ty = self.Gen.StructGen.get_struct_type(full_q)