From 601db9e2651c95848eea46b2e2e567e01eaa169f Mon Sep 17 00:00:00 2001 From: TermiNexus Date: Thu, 20 Aug 2026 05:01:21 +0800 Subject: [PATCH] =?UTF-8?q?fix(gen):=20from-import=20=E6=A8=A1=E5=9D=97?= =?UTF-8?q?=E5=90=8D=E6=88=AA=E6=96=AD=E5=90=8E=E5=86=8D=E6=9F=A5=20SHA1?= =?UTF-8?q?=EF=BC=88=E9=9D=9E=20NUL=20=E7=BB=93=E5=B0=BE=E9=80=80=E5=8C=96?= =?UTF-8?q?=E8=A3=B8=E5=90=8D=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit undefined symbol: _op_head 根因:lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾,后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。ExprGenName 的 from-import 全局查找直接用 该值 LookupSha1ByModName → 整串查不到 → _mangle_name_with_sha1(None) 退化裸名 → 引用 @_op_head 而非 @._op_head → 链接 undefined (tokens 定义端已带 SHA1 前缀)。ExprGenAttr 别名解析同病。 修复:ExprGenName 新增 _cut_from_import_mod(截断到空格/冒号/NUL), 两处 from-import 分支截断后再查 SHA1;ExprGenAttr 别名解析内联截断。 对齐 CallGenBase._lookup_sha1_from_modname_raw / ExprGenCdef 既有截断逻辑。 --- App/lib/core/Gen/ExprGenAttr.vp | 12 +++++++++- App/lib/core/Gen/ExprGenName.vp | 41 +++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/App/lib/core/Gen/ExprGenAttr.vp b/App/lib/core/Gen/ExprGenAttr.vp index 46f4d63..6490b79 100644 --- a/App/lib/core/Gen/ExprGenAttr.vp +++ b/App/lib/core/Gen/ExprGenAttr.vp @@ -248,11 +248,21 @@ class ExprGenAttr(ExprGenBase.ExprGenBase): # 得原始模块名。否则 _lookup_module_sha1("GenGenerator") 查不到(Sha1Store # 用原始模块名)→ 退化裸名 → 全局带 SHA1 前缀后 undefined symbol。 # 别名属性访问(GenGenerator._g_gen = gen)依赖此解析才能命中目标模块定义。 + # 注意:lookup_from_import 返回指针非 NUL 结尾,须截断到空格/冒号/NUL + # 再查 SHA1(否则整串 "lib.core.Gen.Generator Config:lib... " 查不到)。 if trans._from_imports is not None: orig_mw: str = HandlesImports.lookup_from_import( trans._from_imports, mod_path_w, 0) if orig_mw is not None: - mod_path_w = orig_mw + oml_a: t.CSizeT = 0 + while orig_mw[oml_a] != ' ' and orig_mw[oml_a] != '\0' and orig_mw[oml_a] != ':': + oml_a += 1 + if oml_a > 0: + om_buf_a: str = pool.alloc(oml_a + 1) + if om_buf_a is not None: + string.strncpy(om_buf_a, orig_mw, oml_a) + om_buf_a[oml_a] = '\0' + mod_path_w = om_buf_a # 检查是否是已导入模块 if HandlesImports.is_module_imported(trans._imported_modules, mod_path_w) == 0: return None diff --git a/App/lib/core/Gen/ExprGenName.vp b/App/lib/core/Gen/ExprGenName.vp index cd2f9e1..a5ccc40 100644 --- a/App/lib/core/Gen/ExprGenName.vp +++ b/App/lib/core/Gen/ExprGenName.vp @@ -44,6 +44,31 @@ import lib.core.Handles.ExprCallCtor as ExprCallCtor class ExprGenName(ExprGenBase.ExprGenBase): """Name/Subscript/下标访问""" + def _cut_from_import_mod(self, pool: memhub.MemBuddy | t.CPtr, + raw: str) -> str: + """截断 lookup_from_import 返回的模块名到独立缓冲 + + lookup_from_import 返回指向 from_imports 内部的指针(非 NUL 结尾, + 后随空格分隔的其他条目,如 "ast.tokens TokenType:ast.tokens ...")。 + 不截断则 LookupSha1ByModName 收到整串查不到 → mangle 退化裸名 → + 全局引用不带 SHA1 前缀 → 链接 undefined symbol(_op_head 根因, + 对齐 ExprGenCdef._lookup_cross_module_cdefine 的截断逻辑)。 + 截断到空格/冒号/NUL;raw 无效返回 None。 + """ + if raw is None: + return None + mbl_c: t.CSizeT = 0 + while raw[mbl_c] != ' ' and raw[mbl_c] != '\0' and raw[mbl_c] != ':': + mbl_c += 1 + if mbl_c == 0: + return None + buf_c: str = pool.alloc(mbl_c + 1) + if buf_c is None: + return None + string.strncpy(buf_c, raw, mbl_c) + buf_c[mbl_c] = '\0' + return buf_c + def translate_name_value(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, node: ast.AST | t.CPtr, @@ -109,9 +134,13 @@ class ExprGenName(ExprGenBase.ExprGenBase): fi_mod_raw: str = HandlesImports.lookup_from_import( trans._from_imports, nm_id, 0) if fi_mod_raw is not None: - # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰 + # 带源模块 SHA1 前缀精确查找,避免多模块同名全局后缀匹配串扰。 + # fi_mod_raw 非 NUL 结尾,先截断再查 SHA1(否则整串查不到退化裸名) + fi_mod_cut: str = self._cut_from_import_mod(pool, fi_mod_raw) + if fi_mod_cut is None: + fi_mod_cut = fi_mod_raw fi_gv_q: str = HandlesFunctions._mangle_name_with_sha1( - StubMergerStore.LookupSha1ByModName(fi_mod_raw), nm_id) + StubMergerStore.LookupSha1ByModName(fi_mod_cut), nm_id) fi_gv: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( trans.Module, fi_gv_q) if fi_gv is not None and fi_gv.Ty is not None: @@ -297,9 +326,13 @@ class ExprGenName(ExprGenBase.ExprGenBase): # stub 已注入全局(精确类型)→ 直接引用;未注入 → fail-fast # (不再创建 external i8* 声明,否则 llc 报 "use of undefined value", # 静默回退掩盖 stub 未注入的上游根因) - # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰) + # 带源模块 SHA1 前缀精确查找(避免多模块同名全局后缀匹配串扰); + # fi_mod 非 NUL 结尾,先截断再查 SHA1(否则退化裸名 → undefined) + fi_mod_cut2: str = self._cut_from_import_mod(pool, fi_mod) + if fi_mod_cut2 is None: + fi_mod_cut2 = fi_mod gv_fi_q: str = HandlesFunctions._mangle_name_with_sha1( - StubMergerStore.LookupSha1ByModName(fi_mod), fi_gname) + StubMergerStore.LookupSha1ByModName(fi_mod_cut2), fi_gname) gv_fi: llvmlite.GlobalVariable | t.CPtr = HandlesExpr.find_global_in_module( trans.Module, gv_fi_q) ref_fi: llvmlite.Value | t.CPtr = None