fix(tpv): 泛型污染检测改 token 边界匹配(根治 strstr 误杀合法特化)

- _list.vp L57 elem_ptr: T | t.CPtr 在 list[AST|t.CPtr] 特化时被误报污染:strstr('e9dfb296a8674aee.AST|t.CPtr', 'T') 把 AST 内部字符 T 当参数名

- 新增 _str_contains_ident:独立标识符检测(两侧非字母/数字/_),实参内部字符不算污染

- T→T 完全自映射仍直接报错(明确污染);子串场景按边界判定
This commit is contained in:
TermiNexus committed 2026-08-28 15:06:30 +08:00
1 parent 27ba74c720
commit 8445af93d2
1 file changed
+43 -1
+43 -1
View File
@@ -310,6 +310,42 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
return res_c
# ---- 6. 查不到:保持原样 ----
return type_name
def _str_contains_ident(self, s: str, ident: str) -> int:
"""检查 s 中是否包含独立标识符 ident(两侧非字母/数字/下划线)
用于泛型实参污染检测:单字符参数名(如 'T')在实参串 "AST|t.CPtr"
中作为 AST/CPtr 内部字符出现时不算污染——必须两侧是边界
(空格/|/[/]/,等)才算独立标识符。strstr 子串匹配会把实参内部
的 'T' 误判为参数名 → 合法特化 list[AST|t.CPtr] 被误杀。
"""
if s is None or ident is None or ident[0] == '\0':
return 0
s_len: t.CSizeT = string.strlen(s)
id_len: t.CSizeT = string.strlen(ident)
if id_len == 0 or s_len < id_len:
return 0
i: t.CSizeT
for i in range(s_len - id_len + 1):
if string.strncmp(s + i, ident, id_len) != 0:
continue
# 左边界:i==0 或前一字符非标识符字符
left_ok: int = 1
if i > 0:
lc: t.CChar = s[i - 1]
if (lc >= 'a' and lc <= 'z') or (lc >= 'A' and lc <= 'Z') \
or (lc >= '0' and lc <= '9') or lc == '_':
left_ok = 0
right_ok: int = 1
if i + id_len < s_len:
rc: t.CChar = s[i + id_len]
if (rc >= 'a' and rc <= 'z') or (rc >= 'A' and rc <= 'Z') \
or (rc >= '0' and rc <= '9') or rc == '_':
right_ok = 0
if left_ok != 0 and right_ok != 0:
return 1
return 0
def _parse_type_string(self, pool: memhub.MemBuddy | t.CPtr,
type_str: str,
ctx: t.CInt) -> ast.AST | t.CPtr:
@@ -1265,7 +1301,13 @@ class TypeGenResolve(TypeGenBase.TypeGenBase):
gp_j: t.CSizeT
for gp_j in range(gp_n):
gp_pn: str = tpn_g.get(gp_j)
if gp_pn is not None and string.strstr(gp_ta, gp_pn) is not None:
# token 边界匹配(非 strstr 子串):实参串中必须出现
# "独立标识符"参数名(两侧非字母/数字/_)。否则 strstr
# 把实参内部字符误判为参数名——"e9dfb296a8674aee.AST|
# t.CPtr" 含 'T' 字符但 T 在 AST/CPtr 内部不是独立
# 参数名 → 合法特化 list[AST|t.CPtr] 被误杀(_list.vp
# L57 elem_ptr: T | t.CPtr 根因)。
if gp_pn is not None and self._str_contains_ident(gp_ta, gp_pn) != 0:
polluted = 1
break
if polluted != 0: