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
|
d0c7b9c77c
|
chore: 改名同步 TransPyV -> ViperC(.gitignore/文档/脚本)
|
2026-10-12 15:02:13 +08:00 |
|
TermiNexus
|
9b93586eec
|
docs: README 随改名同步(ViperC/viperc.exe/__vpcbuild__)并纠正过时内容
- w32.* -> win32.*(中文前提条件/对比表、英文 Prerequisites/对比表 共 4 处)
- 规模数字按实测刷新:App 82 文件 63,783 行;Gen 54 文件 47,297 行;
Phase 6/5,339;Stub 9/6,207;Projectrans 3/712
- 自测套件位置纠正:不在本仓库,位于工作区根 Test\(独立仓库,97 工程 129 个 .vp),
由 Test\SequentialRegressionTest.py 驱动;删除已不存在的 Test/{App,NegativeTest,Sha1Test} 描述
- 工作区布局补 Test\ 与 exe\,修正 ViperC\ 对齐
|
2026-10-12 14:48:47 +08:00 |
|
TermiNexus
|
023a22af08
|
chore: 工程改名 TransPyV -> ViperC(输出 viperc.exe,构建目录 __vpcbuild__)
|
2026-10-12 14:28:52 +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 |
|
TermiNexus
|
948e1855a6
|
fix(gen): 跨模块 vpi 查询只在加载成功时记"已加载"备忘(修漏检回归)
A2 引入的 lookup_ret_kind_via_vpi 会在 life_of_expr(判右值生命期,可能在极早的翻译阶段)
里触发对方模块 vpi 的按需加载,但它沿用 _vpi_escape_packed 的旧写法:**无论加载成功与否**
都把该模块记入 _vpi_escape_module_loaded 备忘。于是当那个时刻 vpi 还没生成/打不开时,
该模块被毒化成"已加载",之后所有共用这条备忘的跨模块查询(逃逸摘要 esc=、willFree wf=)
都跳过真正的加载 → 缓存恒空 → 判据静默失效。
现场:EscapeXmodTest(跨模块 esc)与 NewLifetimeWillFreeTest(跨模块 wf)双双漏检,
即"应拒绝却通过"。同模块用例不受影响,故更隐蔽。
修法:两处加载点都改为 _ensure_vpi_ret_annot_loaded 返回非 0(= 真加载/已缓存)才
_vpi_escape_mark_module;失败直接返回 0,留给后续查询重试。
- lookup_ret_kind_via_vpi(新代码,回归根源)
- _vpi_escape_packed(既有同款隐患,一并修)。
|
2026-10-10 11:25:43 +08:00 |
|