Commit Graph
795 Commits
Author SHA1 Message Date
TermiNexus 444e87dd7d fix(gen): callable[[]](省略返回类型)按默认 int(i32) 注册函数指针签名,修间接调用签名缺失 fail-fast 2026-10-13 13:26:51 +08:00
TermiNexus d3997e0746 fix(gen): 函数指针变量别名(f2: rawptr = f)继承已注册的返回类型签名,修 rawptr 间接调用的签名缺失 fail-fast 2026-10-13 13:26:11 +08:00
TermiNexus 32599a08c1 fix(stub): .vpi 读取侧复刻字段标记判定(volatile/pointee-volatile/const/字节序),跨模块不再丢字段标记 2026-10-13 12:30:23 +08:00
TermiNexus 37c4b0da3b feat(gen): 字节序 bswap 代码生成——字段/局部变量/数组元素读写处成对 llvm.bswap(仅 BigEndian 且 16/32/64 位整数) 2026-10-13 12:30:05 +08:00
TermiNexus 5d15d01e21 feat(gen): 支持 t.BigEndian / t.LittleEndian 字节序描述符(注解识别 X|marker 并把字节序登记到 FieldEntry.ByteOrder,暂不生成 bswap) 2026-10-13 12:17:02 +08:00
TermiNexus 3ca2165fd9 feat(gen): 指向同型聚合的指针→同型聚合值允许隐式值拷贝(裸类形参 T* ABI 的直接赋值仍按值拷贝) 2026-10-13 10:30:15 +08:00
TermiNexus b859f8a136 fix(gen): CDefine 常量(含 mod.N 属性形态)拓宽方向单独判定——负值 sext、非负 zext,修 zlib 窗口尺寸被 sext 成负数与 Z_DEFAULT_COMPRESSION->255 2026-10-12 21:48:05 +08:00
TermiNexus 22475e0fda fix(gen): 逃逸检查把模块级(根 scope)变量判为 LIFE_STATIC,修模块级数组 return 误判帧逃逸(pyzlib_error_msg) 2026-10-12 21:23:23 +08:00
TermiNexus c0ff5c9d96 fix(gen): 复合赋值取消「右值有符号 vs 左值无符号」拦截,与二元 x = x op y 口径一致(修 sizet += int 误报) 2026-10-12 21:16:50 +08:00
TermiNexus c9562a6e04 feat(gen): 一元 +/-/~ 按符号性提升——u 类不提升(保持原位宽),i 类提升到 i32 防负数陷阱 2026-10-12 21:10:06 +08:00
TermiNexus d206abf3e1 chore: 全仓同步 w32→win32 模块改名与 range(int(...)) 显式收窄适配 2026-10-12 20:59:11 +08:00
TermiNexus ea2af739dd feat(gen): range 边界与循环变量统一提升到至少 i32(取消 u8/u16 循环变量档),u64 边界保持 i64 2026-10-12 20:57:12 +08:00
TermiNexus 00bf7ebf38 fix(gen): 非负 define 常量按最小位宽的无符号位模式参与宽化/比较(修 range(50000) 迭代 0 次) 2026-10-12 20:52:52 +08:00
TermiNexus e3743b185f fix(gen): zip/enumerate 的 range 源工作位宽随参数(仿 for-range),修 range(3) 被 i64 索引误判窄化 2026-10-12 20:24:50 +08:00
TermiNexus 54b239747e chore(gen): 清理「按值物化」残留注释(裸类形参即 T*,非值语义槽) 2026-10-12 20:03:10 +08:00
TermiNexus ae12ae8581 Revert "feat(gen): 裸类形参按值物化(值语义),调用方 ABI 不变"
This reverts commit 87914b0a51.
2026-10-12 19:56:02 +08:00
TermiNexus 001f8afc37 fix(gen): 常量适配限定为位运算,算术一律按 C 语义拓宽(修 i8 乘法回绕致 memhub 不变式误报) 2026-10-12 19:40:13 +08:00
TermiNexus e7b05c6a3d fix(gen): 三元表达式两支统一按常量无损适配,修 i8 表元素 vs 字符字面量被抬成 i32 的窄化误报 2026-10-12 19:27:58 +08:00
TermiNexus 3d638927d5 fix(gen): 移位的工作位宽不计入计数宽度,修 ushort 表达式被抬成 32 位后赋回 ushort 误报窄化 2026-10-12 19:22:36 +08:00
TermiNexus 4a66aa7fd2 feat(gen): 二元运算采用目标感知工作位宽(仿 C:算到目标位宽;移位只提升左操作数),隐式窄化仍禁止 2026-10-12 18:53:50 +08:00
TermiNexus 9d02cc4684 fix(gen): 移位按 C 语义把左操作数提升到 int,且移位数不参与常量适配(修 uchar<<8 误报) 2026-10-12 18:42:54 +08:00
TermiNexus 65c72fd55c fix(gen): 二元运算按常量无损适配另一侧位宽,修 crc(uint)^0xFFFFFFFF 被抬成 64 位 2026-10-12 18:32:55 +08:00
TermiNexus 8453698f66 chore(gen): ExprGenBase 残留清理(range(int()) 与 TPV->VPC 注释) 2026-10-12 18:25:56 +08:00
TermiNexus 74fafb3b56 fix(gen): 整型字面量宽度按值推导(新增 u32 档)+ 显式宽度严格校验 2026-10-12 18:25:38 +08:00
TermiNexus f044d94e90 fix(gen): -x/~x 对编译期常量折叠,修负字面量被隐式窄化误拦 2026-10-12 18:25:24 +08:00
TermiNexus 87914b0a51 feat(gen): 裸类形参按值物化(值语义),调用方 ABI 不变 2026-10-12 18:25:04 +08:00
TermiNexus d7a5f7e68b fix(gen): 值语义聚合槽豁免改为类型级判定,去掉易漏判的槽身份比较 2026-10-12 16:56:03 +08:00
TermiNexus 7c11c589f7 fix(gen): 值语义聚合槽允许隐式值拷贝,修 self.field = param 的 Foo* -> Foo 误报 2026-10-12 16:42:52 +08:00
TermiNexus 3384941cd1 chore: 改名同步 TransPyV -> ViperC(源码/配置内的纯替换) 2026-10-12 15:06:28 +08:00
TermiNexus 4e46a25ab1 fix(gen): define 位宽/整数提升/移位/AugAssign 规则收敛,修 va_list 与 traceback 卡死
- define 位宽:cdefine_decl_bits 单一裁决(注解 → 右侧强转 → 值最小可存宽度),定义方与 VpiReader 两处跨模块注册共用;lookup_cdefine_bits 取最后一条非零记录;存储即截断;使用侧改按声明位宽;通用求值器加编译期除零/移位越界 fail-fast
- 消除对无符号强转加宽方向的依赖:define_min_width 改 (value>>32)==0,截断改左移+算术右移,修 TPC/TPV 判定不一致导致 0x80000000 误判 64 位
- 整数提升:算术/移位、比较、一元 +/-/~ 提升到 i32;位运算保持同宽不提升
- AugAssign:y 有效宽度须 <= x、禁 y 显式有符号而 x 无符号;移位计数静态范围检查
- 函数入口复位 va_list 状态与 willFree 失效槽表(FuncGenDef/FuncGenMixin/VarGenMixin 等)
- BuildPipeline:traceback 逐行扫描改 span 判定,去掉对全文 strlen 的 O(n^2)
2026-10-12 12:37:48 +08:00
TermiNexus be4db7b5d1 fix(narrow): StmtGenMixin exc_code 显式 int(cst_r.int_val)
ast.Constant.int_val 为 int64,exc_code 为 int(并传入 const_int32),改用显式 int(...)
2026-10-11 10:07:37 +08:00
TermiNexus 985983391b fix(narrow): ClassGenBase 方法元数据指针声明 int* 而非 t.CPtr
flags_ptr/flags_ptr2 被显式 (int*)(...) 赋值但声明为 t.CPtr,下标元素被判为 i8,与 i*4 的 32 位步长及位标志语义不符(且 >127 的值会读出符号错误);声明改为 int*
2026-10-11 10:04:19 +08:00
TermiNexus 3b9deb08d8 fix(narrow): ClassGenEnum RenumClassVariantCounts 元素读取改用 int(...)
n_first_v(1029) 与 vcount(1010/1055) 承接 sizet* 元素,原先 64->32 隐式窄化;改用显式 int(...) 保持原截断语义
2026-10-11 10:00:05 +08:00
TermiNexus 7468b007f7 fix(narrow): ClassGenEnum pos_max 加宽为 sizet
pos_max 承接 variant_field_sizes 的 sizet 元素,仅与 sizet 比较并流入 sizet();原 int 触发 64->32 隐式窄化
2026-10-11 09:54:18 +08:00
TermiNexus 3c0d3d13b5 fix(narrow): 清理注解式整数窄化(Converter/TypeGenCType/CallGenLeafKit/ClassGenEnum)
CDefine 查询返回 int64 处按下游用法定型:回传给 int 的用显式 int(...),流入 int64 目标的加宽为 int64;sizet 数组元素赋给 int 的用 int(...)
2026-10-11 09:51:08 +08:00
TermiNexus 966fc3b8f5 fix(narrow): BuildPipeline.ensure_dir 消除隐式窄化(int(path_len) / char(saved))
buf[i] 元素为 i8,saved 由 int 改为 char 并用 char(ch) 显式收窄;plen 由 sizet 显式 int(path_len) 收窄
2026-10-11 09:42:39 +08:00
TermiNexus 77f4a25055 fix(narrow): CallGenFd 的 fd_can 改用 int(len(...)) 消除 64->32 隐式窄化 2026-10-11 09:38:24 +08:00
TermiNexus 82ad5da7c7 fix(narrow): len() 结果赋给 int 的形参/默认值计数改用显式 int(...)
FuncGenDef 的 fd_param_count/fd_default_count/tfd_param_count/tfd_default_count 与 ClassGenVTable 的 md_param_count/md_default_count 原本直接接收 len()(sizet),触发隐式窄化;改 int(len(...)) 保持原有截断语义
2026-10-11 09:34:43 +08:00
TermiNexus d023e9932d fix(narrow): StructGenMixin 守卫候选与归纳区间常量改用 int64,消除 64->32 隐式窄化
kv/lo/hi/k 原本声明为 int 承接 int64(Scratch[...]),触发新禁止的隐式窄化;_AddGuardCand/_PackEscapeClear 的 kv 形参同步拓宽为 int64(打包范围检查需看到完整 64 位值),打包结果处显式 int() 收窄
2026-10-10 22:20:47 +08:00
TermiNexus 41772b4a0c refactor(narrow): 撤销 File.write 实参多余的 ULONG(...) 显式窄化
File.write 形参已改为 sizet,调用点不再需要显式 ULONG 包裹(覆盖 WriteCallSidecar/_phase2_write_cmd/write_ir_to_file/WriteStackMap/TranslateFileGetTrans)
2026-10-10 22:15:49 +08:00
TermiNexus 58951a29a8 fix(narrow): File.write 长度实参加显式 ULONG(...)(避免 64→32 隐式窄化)
fileio.File.write(buf, count: ULONG) 的 count 是 32 位,而实参是 sizet/int64(strlen、pos、ir_len、total 等);规则收紧后为隐式窄化,改为显式 ULONG(...)。本文件其它位置无隐式窄化。
2026-10-10 22:10:01 +08:00
TermiNexus 5bb6538703 feat(types): 禁止隐式窄化(整数 高→低);_tb_read_whole 容量改 sizet
规则收紧(2026-10-10):整数位宽 高→低 隐式窄化一律 fail-fast(CastError),仅两类豁免:① 目标 i1 的真值归一化;② 源是编译期常量且值落进目标位宽。_scalar_convert_reason 的 int↔int 同步改为'目标位宽≥源位宽才 PC_OK'。BuildPipeline._tb_read_whole 去掉 ULONG(sz)+ULONG(2) 的窄化,改 sizet(sz)+2。
2026-10-10 21:57:18 +08:00
TermiNexus 9db3748f68 feat(gen): main 内栈逃逸检查整体豁免(收窄为结构体指针不再采用)
按用户决定:入口 main 的帧生命期=进程生命期,main 内任何栈地址写进长命存储都不报,不再区分结构体/标量。移除上一版为'仅豁免结构体指针'新增的 _TypeIsPtrToStruct/_ExprIsStructPtr,fail_if_life_escapes 只保留 _CurFuncIsEntryMain 短路。嵌套函数不豁免。
2026-10-10 14:46:45 +08:00
TermiNexus 87e0bce5ee feat(gen): 入口 main 内豁免栈上结构体指针的逃逸检查
memhub.MemBuddy(...) 是裸构造(无 __new__),life_of_expr 判定为 LIFE_FRAME;main 里 argparse._mbuddy = mb 把帧内结构体指针写进模块级字段即触发 P3 拦截。入口 main 的帧生命期=进程生命期,其栈上结构体不会被本帧返回后使用,故在 fail_if_life_escapes 放行。仅豁免'结构体指针'(新增 _CurFuncIsEntryMain/_TypeIsPtrToStruct/_ExprIsStructPtr):标量指针(&local、栈数组退让、ret(frame) 返回 int*)仍受检,保持 NewLifetimeFieldEscapeTest / NewLifetimeAnnFieldEscapeTest 等负向工程不回归。
2026-10-10 14:45:07 +08:00
TermiNexus 034293df59 fix(gen): freed_restore/freed_join/freed_capture 补 global 声明,修复野写崩溃
上一提交(eea8111)在 freed_restore 里重新赋值全局指针 _g_freed_slots 却未声明 global,被解析成未初始化的局部变量:is None 判假 → 跳过分配 → 对垃圾地址(0x11)野写,ASan access-violation。为三个新函数统一声明 global _g_freed_slots, _g_freed_count(与 _FreedMark 同口径)。
2026-10-10 14:27:00 +08:00
TermiNexus eea8111e61 fix(gen): willFree 失效槽表补控制流合流,修复分支内 free 泄漏导致的误报
失效表原为平坦单调全局表,无分支合流语义:if 分支体内 free(x) 会把失效态泄漏到合流之后,于是 fileio.vp 的 if ...: free(buf); return None 之后 return buf 误报 LifetimeError(1784eaf 修好 free 的 wf 位后才暴露)。新增 freed_capture/freed_restore/freed_join(pool 快照 + 求交),并在 if(结合 then/else 是否到达合流)与 while/for 的既有 life_* 同点位接入:只有所有到达合流的路径都失效才算失效。
2026-10-10 14:10:53 +08:00
TermiNexus f2cbb658e1 fix(stubgen): vpi 落盘入口统一重建文件级名字窗口,修复 FileFuncNames 悬垂野读崩溃
Phase1 1b-pre / 1b 兜底 / BuildPipeline / Repl 为生成 vpi 各自重新 parse 出独立 AST,但不走 register_file_funcs,导致 is_file_func(range)(_PushInductionEntry)仍读到上一个文件的表 + 已被 reset 的池 → 悬垂指针,ASan access-violation 崩在 HashTable._slot_hash。将 reset_file_name_window + register_file_func_names 收敛到 _GeneratePyiFromAst 唯一入口,覆盖全部 vpi 落盘调用点;Phase2 的重复调用随之移除。
2026-10-10 14:00:41 +08:00
TermiNexus c1d3f62bf0 fix(gen): ret(borrows=...) 支持 0 起序号写法(原来只认形参名)
现场:@life(noescape(a, b), ret(borrows=1)) 报
LifetimeError: @life(ret(borrows=...)) accepts only a parameter name or `none`
—— _RetKindFromTag 的关键字分支只处理 Name(形参名)与 CONST_NONE,遇到整数常量
(形参位置序号)就落到 fail-fast。

修法:Name(形参名 / none)与 Constant(CONST_NONE = 非本帧)先分流,
其余一律交给 _WillFreeArgIndex —— 它本来就同时认"形参名"与"0 起序号"
(与 willFree(...) 同口径,见 includes/stdlib.vp 注释),非法实参在那边 fail-fast。
于是 ret(borrows=x) 与 ret(borrows=0) 等价可用。
2026-10-10 13:27:24 +08:00
TermiNexus 5ec75b2d38 fix(gen): 模块限定函数调用的 ret(borrows=x) 形参位映射错位(A2 跨模块静默失效)
现场:NewLifetimeRetXmodTest 漏检(应拒绝却通过)。诊断(printf 断点,已删)显示
_CallRetKind 完全正确:cls=(none) → 模块分支 → mod_p=retdep2 sha=1 → vpi lookup rk=8。
即契约取到了,错在**下一跳**:life_of_expr 的 borrows 分支用
_CallArgNodeForParam(cl, pi) 把 pi=0 当"接收者"——那是**方法**的语义(形参表含 self)。
`retdep2.IdentBorrow(l)` 是**模块限定函数**(callee 也是 Attribute,但不是方法),
形参 0 就是第一个实参,于是取到了 `retdep2` 这个模块名节点:
life_of_expr(Name retdep2) 查不到变量 → 返回 LIFE_STATIC(≠FRAME)→ 放行。

修法:
- _CallArgNodeForParam 增加 is_method 参数:为 1 时才把 pi=0 映射到接收者、其余偏移一格;
  为 0(模块限定/裸函数)时 pi 直接就是实参下标。
- 新增 _CallIsMethod(trans, cl):接收者是对象变量(_RecvClassName 命中)才算方法调用。
- life_of_expr 的 borrows 分支据此传参。

同模块用例(NewLifetimeRetEscapeTest)与正向用例(NewLifetimeRetOkTest)在此之前"碰巧"
通过/失效——前者走 Name callee 不涉偏移,后者的正例把结果用在本帧内、STATIC 也放行。
2026-10-10 13:00:51 +08:00
TermiNexus 1784eaf906 fix(gen): _WillFreeMergeTag 置位判据写反(is_wf != 0 → == 0),P2 willFree 全面漏检
string.strcmp 相等返回 0,所以 `is_wf != 0` 的含义是"这个标签**不是** willFree"。原来的
`if is_wf != 0: mask |= 1 << idx` 于是:真正标了 willFree 的形参位**永不置位**,而任何别的
标签(noescape/escape/stores/borrows)反而把 willFree 位置 1。

实测证据(本轮编译产物):
- EscapeXmodTest/.tpv_build/.../73b2b3ff01d73ce2.vpi(stdlib)第 9 行
  `def free(p: rawptr) -> t.State: pass` —— 连尾注都没有(wf_mask 为 0 ⇒ 不写 wf=);
- EscapeOkTest/.tpv_build/.../4ccdbfc0e006b3d5.vpi 第 44 行 StoreNS(只标了 noescape)
  却写着 `# wf=1 escn=1`(反向误标)。

后果:跨模块 wf= 通道形同虚设 → 调用点从不"标记实参失效" → P2 全面漏检
(NewLifetimeWillFreeTest / WillFreeKwargTest / WillFreeMethodTest / WillFreeAddrTest 静默通过),
同时 NewLifetimeWillFreeOkTest 是**空过**(根本没有标记发生)。反向误标还可能造成假报。

回归来源:fc797da(A1 把三元 guard 扩成五元时把这行一起改反)。本行判据改为 is_wf == 0,
与同文件 @willFree 兼容分支(strcmp(...) == 0 即相等)的口径一致。
2026-10-10 11:55:57 +08:00