diff --git a/App/lib/core/Gen/Expr/ExprGenOps.vp b/App/lib/core/Gen/Expr/ExprGenOps.vp index 3237c6c..455aab8 100644 --- a/App/lib/core/Gen/Expr/ExprGenOps.vp +++ b/App/lib/core/Gen/Expr/ExprGenOps.vp @@ -402,164 +402,22 @@ class ExprGenOps(ExprGenBase.ExprGenBase): return 1 return 0 return 0 - def _last_dot_tail(self, name: str) -> str: - """取最后一个 '.' 之后的部分(无 '.' 返回 None);用于模块限定名退查""" - if name is None: - return None - dot: str = string.strrchr(name, 46) - if dot is None: - return None - return dot + 1 - def _type_name_unsigned_legacy(self, type_name: str) -> int: - """[旧路径] 类型名是否为无符号整数类型(精确匹配 + CTypedef 展开一层)""" - if type_name is None: - return 0 - # t.CUIntXXT 形式 - if string.strcmp(type_name, "CUInt8T") == 0: return 1 - if string.strcmp(type_name, "CUInt16T") == 0: return 1 - if string.strcmp(type_name, "CUInt32T") == 0: return 1 - if string.strcmp(type_name, "CUInt64T") == 0: return 1 - # 内建无符号别名(非 CTypedef,动态兜底查不到 → 必须显式登记)。 - # CSizeT 此前缺失 → viperio.Buf.write 的 capacity/length 比较生成 - # icmp sgt/sle/slt(应 ult/ule/ult),A5 同族残留根因。 - if string.strcmp(type_name, "CSizeT") == 0: return 1 - if string.strcmp(type_name, "CUIntPtrT") == 0: return 1 - # bool / t.CBool:i1 属无符号语义(should_zext_widen 对 narrow_bits==1 - # 已强制 zext,此处登记仅为与独立真源口径一致)。 - # 原表把 SSizeT 列为无符号(A3 缺陷)——已删:SSizeT 实为有符号。 - if string.strcmp(type_name, "CBool") == 0: return 1 - if string.strcmp(type_name, "bool") == 0: return 1 - # stdint 裸别名(from stdint import *) - if string.strcmp(type_name, "UInt8T") == 0: return 1 - if string.strcmp(type_name, "UInt16T") == 0: return 1 - if string.strcmp(type_name, "UInt32T") == 0: return 1 - if string.strcmp(type_name, "UInt64T") == 0: return 1 - # CUnsigned* 形式 - if string.strcmp(type_name, "CUnsignedChar") == 0: return 1 - if string.strcmp(type_name, "CUnsignedShort") == 0: return 1 - if string.strcmp(type_name, "CUnsignedInt") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLong") == 0: return 1 - if string.strcmp(type_name, "CUnsignedLongLong") == 0: return 1 - # 常见无符号别名 - if string.strcmp(type_name, "BYTE") == 0: return 1 - if string.strcmp(type_name, "UCHAR") == 0: return 1 - if string.strcmp(type_name, "USHORT") == 0: return 1 - if string.strcmp(type_name, "UINT") == 0: return 1 - if string.strcmp(type_name, "ULONG") == 0: return 1 - # [阶段3] CTypedef 动态表兜底:stdint 别名(DWORD/uint32_t 等)走库定义 - # 展开,按 _annot_str_unsigned_legacy 子串规则判断符号性。 - # S2 修正:原实现**只展开一层** ⇒ 多层别名漏判(如 WCHAR→WORD→ - # t.CUInt16T、FSIZE_t→DWORD→t.CUInt32T);改为沿链展开至不动点。 - cur_u: str = type_name - depth_u: int = 0 - while depth_u < 16: - ts_u: str = self.Gen.TypeGenCType.lookup_ctypedef(cur_u) - if ts_u is None or self.Gen.TypeGenCType.CTypedefFound == 0: - # 模块限定名(如 stdint.u32 / builtins.DWORD)退到最后一段重查 - tail_u: str = self._last_dot_tail(cur_u) - if tail_u is not None: - ts_u = self.Gen.TypeGenCType.lookup_ctypedef(tail_u) - if ts_u is None or self.Gen.TypeGenCType.CTypedefFound == 0: - break - if self._annot_str_unsigned_legacy(ts_u) != 0: - return 1 - if string.strcmp(ts_u, cur_u) == 0: - break - cur_u = ts_u - depth_u += 1 - return 0 - def _annot_str_unsigned_scan(self, annot: str) -> int: - """[旧路径·子串表] 纯子串扫描(不做别名链展开) - - 用于复合注解(t.CArray[uint8, 16] / uint8 | t.CPtr), - _type_name_unsigned_legacy 的精确匹配对这类串不适用。 - """ - if annot is None: - return 0 - if string.strstr(annot, "CUInt8T") is not None: return 1 - if string.strstr(annot, "CUInt16T") is not None: return 1 - if string.strstr(annot, "CUInt32T") is not None: return 1 - if string.strstr(annot, "CUInt64T") is not None: return 1 - # 内建无符号别名(同 _type_name_unsigned) - if string.strstr(annot, "CSizeT") is not None: return 1 - if string.strstr(annot, "CUIntPtrT") is not None: return 1 - # 小写 stdint 别名(uint16/uint32/uint64/uint8):复合注解如 - # t.CArray[uint16, 256] 的注解串用大写规则扫不到,需显式识别小写 - # (ide.vp identify_data: t.CArray[uint16,256] 的 word60 误 sext 根因)。 - # 注意不含 "size_t":ssize_t(有符号)包含该子串会误判。 - if string.strstr(annot, "uint8") is not None: return 1 - if string.strstr(annot, "uint16") is not None: return 1 - if string.strstr(annot, "uint32") is not None: return 1 - if string.strstr(annot, "uint64") is not None: return 1 - if string.strstr(annot, "CUnsigned") is not None: return 1 - # bool / CBool:i1 属无符号语义(与 _type_name_unsigned_legacy 同口径) - if string.strstr(annot, "CBool") is not None: return 1 - if string.strstr(annot, "bool") is not None: return 1 - if string.strstr(annot, "BYTE") is not None: return 1 - if string.strstr(annot, "UCHAR") is not None: return 1 - if string.strstr(annot, "USHORT") is not None: return 1 - if string.strstr(annot, "UINT") is not None: return 1 - if string.strstr(annot, "ULONG") is not None: return 1 - # WORD 系:WORD/DWORD/QWORD/WCHAR/FSIZE_t/LBA_t 均为无符号(WORD=t.CUInt16T)。 - # 原表漏 WORD ⇒ 复合别名 `WCHARPTR = WORD | t.CPtr` 被旧判为 signed - # (S2 闸门实测暴露:旧判 signed / 新真源 unsigned,旧错)。 - if string.strstr(annot, "WORD") is not None: return 1 - return 0 - def _is_simple_ident(self, s: str) -> int: - """是否简单标识符(仅标识符字符与 '.',不含空白/运算符/括号/逗号)""" - if s is None: - return 0 - n: sizet = string.strlen(s) - if n == 0: - return 0 - i: sizet = 0 - while i < n: - if s[i] == ' ' or s[i] == '\t' or s[i] == '\n' or s[i] == '\r': - return 0 - if s[i] == '|' or s[i] == '[' or s[i] == ']' or s[i] == '(' or s[i] == ')': - return 0 - if s[i] == '*' or s[i] == ',' or s[i] == '+': - return 0 - i += 1 - return 1 - def _annot_str_unsigned_legacy(self, annot: str) -> int: - """[旧路径] 注解串无符号判定 = 子串扫描 + 裸别名沿 CTypedef 链展开后再扫 - - 为何需要链展开:`_node_type_unsigned` 的 Subscript/Attribute 分支会把 - **裸别名**(`sizet` / `u64` / `WORD` …)当作注解串传进来,而子串表只认 - `CSizeT` / `uint64` 等长名 ⇒ 这些别名此前被漏判(A5 同族)。链展开后 - 其目标(`t.CSizeT` / `t.CUInt64T`)能被子串表命中。 - 复合串(含 '|' / '[' 等)不做链展开,交给子串表。 - """ - if self._annot_str_unsigned_scan(annot) != 0: - return 1 - if annot is None or self._is_simple_ident(annot) == 0: - return 0 - cur: str = annot - d: int = 0 - while d < 16: - ts: str = self.Gen.TypeGenCType.lookup_ctypedef(cur) - if ts is None or self.Gen.TypeGenCType.CTypedefFound == 0: - tail: str = self._last_dot_tail(cur) - if tail is not None: - ts = self.Gen.TypeGenCType.lookup_ctypedef(tail) - if ts is None or self.Gen.TypeGenCType.CTypedefFound == 0: - break - if self._annot_str_unsigned_scan(ts) != 0: - return 1 - if string.strcmp(ts, cur) == 0: - break - cur = ts - d += 1 - return 0 # ============================================================ - # S3 切读(无符号判定块)——**新真源优先**,旧路径降级为兜底 + # S4 去字符串化(无符号判定块)——**真源唯一**,旧字符串路径已删 # - # 真源:TypeGenCType.spec_sign_of_annot(精确名白名单 + CTypedef 链逐层展开)。 - # 切读策略(D5「旧路径留兜底」): - # - 新真源**明确表态**(UNSIGNED/SIGNED)→ 直接采用(不再看旧子串表); - # - 新真源返回 UNKNOWN(类名 / sha1 前缀名 / 未登记别名等尚未覆盖)→ 回退旧路径。 - # S2 的「双写一致性闸门」在切读后已无意义(读就取新真源,比对恒等),故撤除。 + # 真源:TypeGenCType.spec_sign_of_annot(顶层 '|' 分段 → 去空白/外层括号 → + # '*' 后缀 → IDENT[INNER, ...] 取元素 → 去模块限定前缀 → 精确名白名单 → + # CTypedef 链逐层展开,限深 16 防环)。 + # 它已完整覆盖旧路径的能力(含复合注解与别名链),故 S4 直接删掉旧字符串兜底: + # `_type_name_unsigned_legacy` / `_annot_str_unsigned_scan` / + # `_annot_str_unsigned_legacy` / `_last_dot_tail` / `_is_simple_ident` + # —— 那套 strstr 子串扫描正是 A4/A5 假阳性的源头(`BYTEPTR` 含 BYTE 被判 + # 无符号;任何含 `uint32` 的串(含 sha1 前缀 mangled 名)都会命中)。 + # + # 现语义:真源 UNKNOWN = **不表态** ⇒ 两个入口一律返回 0(保持编译器默认的 + # zext/sext 取向)。若日后发现某名字确实是无符号却没被判出,正确处理是 + # **补进 SpecSignFromTypeNameSpan 白名单 / 补 CTypedef 声明**, + # 而不是恢复子串扫描(那会把假阳性一并放回来)。 # ============================================================ def _spec_sign_from_annot(self, annot: str) -> int: """真源入口:注解 → TS_SIGN_*(UNKNOWN 表示不表态)""" @@ -569,11 +427,11 @@ class ExprGenOps(ExprGenBase.ExprGenBase): # # S4 切读:条目的 Spec 由 SpecFromLLVMType 反推(恒 TS_INT)+ SpecWithSign # 按注解切 TS_UINT。因此 `Kind == TS_UINT` 是**注解明确表态无符号**的强信号, - # 可优先于 AnnotClassName 字符串判定直接采用。 + # 可优先于注解名字符串判定直接采用。 # # ⚠️ 反向不成立:`Kind == TS_INT` 既可能是"注解有符号"也可能是"未表态" # (SpecFromLLVMType 默认),**不可**据此断言 SIGNED —— 故只切无符号方向, - # 有符号仍走 AnnotClassName 字符串真源(避免把未表态误判成 signed)。 + # 有符号仍走注解名(Spec.SourceName)真源(避免把未表态误判成 signed)。 # ============================================================ def _entry_spec_unsigned(self, sp: TSpec.TypeSpec | t.CPtr) -> int: """Spec 是否明确无符号整数(TS_UINT);其它一律 0(未表态/不适用)""" @@ -583,27 +441,26 @@ class ExprGenOps(ExprGenBase.ExprGenBase): return 1 return 0 def _type_name_unsigned(self, type_name: str) -> int: - """[S3 切读] 类型名无符号判定:新真源优先,未表态时回退旧路径 + """[S4] 类型名无符号判定:**真源唯一**(旧字符串兜底已删) - 注:旧路径在此**按需**调用(仅新真源不表态时),避免热路径上无谓的 - 子串扫描 + CTypedef 链查表双份开销。 + 真源 UNKNOWN = 不表态 ⇒ 返回 0(非无符号),保持编译器默认的 zext/sext 取向。 """ if type_name is not None: - s: int = self._spec_sign_from_annot(type_name) - if s == TSpec.TS_SIGN_UNSIGNED: + if self._spec_sign_from_annot(type_name) == TSpec.TS_SIGN_UNSIGNED: return 1 - if s == TSpec.TS_SIGN_SIGNED: - return 0 - return self._type_name_unsigned_legacy(type_name) + return 0 def _annot_str_unsigned(self, annot: str) -> int: - """[S3 切读] 注解串无符号判定:新真源优先,未表态时回退旧路径""" + """[S4] 注解串无符号判定:**真源唯一**(旧子串扫描已删) + + 真源按顶层 '|' 分段、去括号/空白、取 `IDENT[INNER]` 的元素、去模块限定前缀, + 再走精确名白名单 + CTypedef 链展开 —— 已覆盖原 `_annot_str_unsigned_scan` + 对复合注解(`t.CArray[uint8, 16]` / `uint8 | t.CPtr`)的全部能力, + 且无子串假阳性。UNKNOWN = 不表态 ⇒ 返回 0。 + """ if annot is not None: - s: int = self._spec_sign_from_annot(annot) - if s == TSpec.TS_SIGN_UNSIGNED: + if self._spec_sign_from_annot(annot) == TSpec.TS_SIGN_UNSIGNED: return 1 - if s == TSpec.TS_SIGN_SIGNED: - return 0 - return self._annot_str_unsigned_legacy(annot) + return 0 def translate_compare(self, builder: llvmlite.IRBuilder | t.CPtr, pool: memhub.MemBuddy | t.CPtr, mod: llvmlite.LLVMModule | t.CPtr,