Repository navigation
Inimerse 0.5.2
0.5.2 是一个修栈的版本:一处真实存在的、只在 Windows 上编译的运行时缺陷,在 Linux 上拿到的是全绿的门禁。它同时给门禁添了第十三个阶段,并落了一大轮文档诚实化。语言与运行时语义没有变化。
门禁报的 PASS,是「我看了」还是「我没看」?
基线
| 项 | 值 |
|---|---|
| 版本 | 0.5.2 |
| 测试 | 发布点 v0.5.2(git rev-parse --short 'v0.5.2^{commit}')上:Linux 148 / 148 真通过(本地十三阶段门禁,0 跳过)。0.5.1 发布点 v0.5.1 → 4e444dd 上同样是 148 / 148、当时是十二阶段 |
相对 v0.5.1 |
git rev-list --count 'v0.5.1^{commit}'..'v0.5.2^{commit}' —— 本行不写这个字面量:写下一个数就多一个提交,而那个数正是要数的提交数。在 751b2a0 上量是 76(初稿写 74,那是在 88e9338 上量的 —— 数与 ref 错位,见 docs/AUDIT.md §1.74) |
修了什么
-
Windows 的
re_seq用自递归吃掉栈,25 个字符就崩。match_long_pattern_runtime自报code=0xC00000FD(STATUS_STACK_OVERFLOW)。最小复现不是 fixture 里的 2030,而是 25:s = "a"×25 ; match(s, "^" + "a"×25 + "$zzz")同一长度、以
"$"结尾的那一行不崩。机制是量出来的,不是读出来的:崩溃那一刻栈上有 26 个活着的re_seq帧,它们的返回地址彼此恰好相隔0x8080= 32896 B —— 与序言反汇编逐位吻合(push r15 / mov $0x8038,%eax / push r14,r13,r12,rbp,rdi,rsi,rbx / call ___chkstk_ms / sub %rax,%rsp⇒ 8×push(64) + 32824 + 8)。SizeOfStackReserve 0x200000(2 MiB)。这里有三个数,它们量的是不同的东西,必须分开写:26 个re_seq帧自身占 26 × 32896 = 855296 B(2 MiB 的 40.8%);崩溃瞬间整条栈已耗 2069776 B = 98.70%(rsp=0x407af0对可读顶0x601000);进下一帧还差 5520 B(帧 32896 −rsp到栈基0x401000的余量 27376)。三者不互相推导 —— 独立核对:2069776 + 32896 = 2102672,超出 2 MiB 预留 5520 B。本节初稿把余量写成0x60f0(24816)、差写成 8080,是0x407af0 − 0x401000这一步算错的连带值(实为0x6af0= 27376),已更正。2030 与 25 两个输入得到逐项相同的读数(同一RSP=0x407af0、同样 26 帧)⇒ 深度由栈预算封顶,与输入长度无关。修法是把三处纯尾调用改写成既有的
for (;;)迭代($分支、交替分支、无量化续接),新增一个quant标志分辨「无量化」与「有量化」两条路。有量化的那条仍然递归,深度由嵌套决定 —— 这一点写在这里,是因为它正是「修法只治了这一条路」的边界。src/runtime/runtime.c+32/−6。判据三条,缺一不可:① 该 CTest 由
***Exception: SegFault变Passed;② 反向验证在同一棵树上做(换回修复前字节、增量重建 ⇒ 重新 SEGFAULT);③ 同树 Windows 全量 ctest 里变的是且只是目标那一条(修复前98% tests passed, 3 tests failed out of 128:19 process_probe、136 count_builtin_runtimeSEGFAULT、137 match_long_pattern_runtimeSEGFAULT ⇒ 修复后98% tests passed, 2 tests failed out of 128)。语义判据另钉住「一律返回 false」的假修法过不去:第 10 行必须答impossible=false、第 11 行必须答possible=true。
门禁新增
-
第十三个阶段
orphan-targets。tools/check_orphan_targets.py(新,226 行):每一个add_executable出来的目标都必须被至少一条 CTest 跑到。38 个目标里 37 个被跑到、1 个有写明理由地豁免(websocket_probe—— WebSocket 帧层未实现,探针没有可断言的东西,见docs/API.md§「预留」两行)。它与 0.5.1 的orphan-fixtures是同族但方向相反:那个问「有没有输入没人跑」,这个问「有没有产物没人跑」。造它的过程里有一条教训值得留在这里:按测试名匹配目标名是错的尺子 ——
literal_resolve_probe/resolve_timeout_probe的测试名是literal_resolve_runtime/resolve_timeout_runtime,第一次用错尺子误报了三个。现在它读的是$<TARGET_FILE:…>与add_test的真实引用关系。 -
tools/gate.sh --required-for:这一笔改动能影响哪些阶段。 它从STAGE_SPECS的真实注册表派生,而不是按名字手写 glob —— 后者会漏掉tools/im_diff_fuzz.py、node_suites/、dsh-inimerse/、Infiverse_standard/oauth_loop这四个名字不像 checker 的阶段入口。用法:--required-for <ref>回答「工作区相对<ref>变了什么」,--required-for <base>..<head>回答「这个提交区间变了什么」。两种形式回答的是两个不同的问题,输出里各自自报。
一大轮文档诚实化
-
docs/AUDIT.md+533/−32(新增 §1.65–§1.74)、docs/HANDOFF_INFIVERSE.md+196/−0(新)、docs/DECFY_DESIGN.md+70/−29、docs/BOARD.md+9/−7、docs/STATUS.md+5/−5,另有docs/README.md、docs/HYGIENE.md、docs/RELEASE_0.5.1.md、docs/streams/json-min-nul-escape.md各 +1/−1。(初稿写+565/99/16/10并把 HANDOFF 写成+196:数都对,但那是「改动行数」= insertions + deletions,而同一个+号在+196那里读作 insertions 也成立 —— 一个记号两个意思。出处:git diff --numstat v0.5.1 751b2a0 -- docs/。)这一轮治的是一族同形状的缺陷,它们都不改变任何行为,只改变一个断言能不能变红。值得单独点名的一条,因为它自己证明了自己:
一个用字面量声明「该字面量全库零命中」的句子,写下那一刻就把自己证伪了。
docs/AUDIT.md§1.65 与docs/STATUS.md都曾写「全库grep -rn 'Total Tests: 131' docs/ tools/零命中」—— 而写下这句话本身就往仓库里加了一处命中。现在的写法是直接给出处,不写「几处」。同族的其余几条(都进了 §1.65–§1.73):分母是「跑它的那一刻那个工作区的索引」而不是任何 ref(
check_text_integrity的822vs823);git ls-files 'src/**/*.c'给 106 而':(glob)src/**/*.c'给 114(不写:(glob)时**根本不是**);文档里指向CMakeLists.txt/tools/gate.sh的行号必须带 ref 或内容锚(同一个目标在docs/AUDIT.md里已经有过三个号码,每次写下时都是对的);改动的单位是「段落」而不是「被点名的那一行」(同一个段落里,改了一处而另一处留着,出现过三次)。
平台
- Windows:与 0.5.1 相同 —— hub 为减配版本,9 个 POSIX hub 回归测试显式
DISABLED(按维护者裁定,移植未做),两个 xlang 桥(Java / Python)按设计以退出码 77 跳过。本版的引擎修复只作用于 Windows(见下)。 - Linux:完整功能,十三阶段门禁全绿。
资产
| 平台 | 资产 |
|---|---|
| Linux | inimerse-0.5.2-Linux-x86_64.tar.gz、inimerse-0.5.2-Linux-x86_64.zip、inimerse-0.5.2-Linux-x86_64.deb、SHA256SUMS |
| Windows | inimerse-0.5.2-Windows-x86_64.zip(含 bin/inimerse.exe、bin/aot-native.exe、bin/inim.py)、InfiverseSetup-0.5.2.exe(Inno Setup 7 装机包)、SHA256SUMS-Windows |
SHA256SUMS 与 SHA256SUMS-Windows 里都是裸文件名,在下载目录里 sha256sum -c 可直接校验。
诚实边界
- Linux 上的十三阶段全绿,对本版那处引擎修复不提供任何证据。
CMakeLists.txt:429在if(WIN32)里选src/runtime/runtime.c,:437的else()选:438的src/runtime/runtime_posix.c(后者没有re_seq,用的是 libcregcomp)⇒ Linux 门禁根本不编译被改的那个文件(nm build/inimerse | grep -c 're_seq'= 0)。这条不是推测,是本版 §1.71 量出来的:src/下 114 个受管.c里,Linux 构建只给 102 个产出.o,缺的 12 个全部只出现在CMakeLists.txt:426-436的if(WIN32)块内。「Windows 运行时只在 Windows 上编译」是合理的;不合理的是门禁把「没编译」报成 PASS。 - 修复的证据来自一棵
RelWithDebInfo树,帧大小0x8080未在-O3 -DNDEBUG(发布配置)上量过 —— 量不到就写「未量」,不写成量到了。 - 登记但未修:
src/runtime/runtime.c里pos[4096]的回溯读没有守卫(写有if (count < 4096),读t = pos[count - 1]没有)—— 它被「25 个字符就崩」证伪为本次崩溃的原因,仍是独立缺陷;re_seq的 32896 B 帧仍然存在,封顶嵌套量化 / 分组的深度;count_builtin_runtime在 Windows 上同样0xC00000FD,但[stack] #8是0x6ed8(≠re_seq的0x8038)、re_seq断点在该 fixture 上计数 0、原始栈扫描定位到compile_expr自递归(32 帧)⇒ 那是既有缺陷被新测试暴露,不在本版修。 orphan-targets证明的是「每个目标都被某条 CTest 引用」,不是「那条测试断言了有意义的东西」;它的1 allowed是一条有理由的豁免,而豁免名单会退化成免责名单 —— 与orphan-fixtures的4 allowed是同一个风险。--required-for的映射只在tools/gate.sh的注册表里,它不解析任何文件内容:一个阶段「受影响」是因为改动落进了它读的那棵子树,不是因为它真的会红。单参形式看的是工作区(干净树上答0 stage(s)且退 0),所以它自报回答的是哪个问题 —— 但「零个阶段」在一个敲错的调用里仍然是危险的答案。- 文档里的行号引用仍然可能过期:本版把
docs/AUDIT.md里指向tools/gate.sh与CMakeLists.txt的行号换成了锚或带 ref 的形式,但同一个类的其余拷贝还在别的文档里(docs/BOARD.md/docs/STATUS.md/docs/DECFY_DESIGN.md合计十几行),本版只登记、没有全部重取。 docs/SYNTAX.md§「核心高频」那一行缺平台标注:file_exists与timer_ms只由src/mod/io_mod.c注册,而io_mod在 POSIX 上是空桩 ⇒ 那两个名字在 Linux 上是unknown builtin function;mkdir与list_dir则是同一个名字两个生产点(Windows 走io_mod、POSIX 走runtime_posix)。该行还自称「有vtest覆盖」,对这四个名字全不成立。本版只登记、未裁定。- 这个仓库里版本号有四个生产点,没有任何东西让它们保持同步:
CMakeLists.txt:8(set(INIMERSE_PACKAGE_VERSION …))、installer.iss:7(AppVersion=)、installer.iss:13(OutputBaseFilename=)、以及本文件与历史发版说明里的资产名。本版之前,前两个里只有CMakeLists.txt被升过 ——installer.iss:7停在0.5.1、installer.iss:13是不带版本号的InfiverseSetup,而 0.5.0 / 0.5.1 / 0.5.2 三份发版说明都写InfiverseSetup-0.5.X.exe,全库没有任何脚本产出那个名字。本版把AppVersion与OutputBaseFilename都改到0.5.2,但装机包在本机无法构建、因而这条改动没有被任何东西验证过(只在 Windows + Inno Setup 上才能验)。下一次升版本时,这四个点要一起看。 v0.5.2这个 tag 在本轮里被移动过两次,现在冻结。 第一次:它先打在751b2a0,推上去之后才发现基线表那一行的字面量(74)是在另一棵树(88e9338)上量的,而那个数在被数的提交里写下就必然错位。第二次:一份独立复核(ivory-ember 对751b2a0)发现本文件的崩溃算术与docs/STATUS.md的引擎代码行都是错的,而发版说明是用户真正读的那个产物,所以 tag 移到把这份说明改对了的那个提交。冻结的判据是「这份说明自己说对了」,不是「已经推过」 —— 从git rev-parse --short 'v0.5.2^{commit}'给出的那个提交起,此后发现的任何问题只进main,并且要在docs/STATUS.md的「已发布点」那一行里被点名;想看这一版发布时仓库是什么样,用git show 'v0.5.2^{commit}':<path>。- 本文件此前是孤儿文档:
git grep 'RELEASE_0\.5\.2'在全库 0 命中(check_links只验「链能不能解析」,不验「文件有没有人引」—— 而本版新增的第十三个阶段问的正是「有没有产物没人跑」,同一个问题在文档侧没有对应的检查器)。现在docs/STATUS.md的「已发布点」那一格有一个入链。没有为它开新阶段:名录式检查会退化。 docs/RELEASE_0.5.1.md里 WindowsTotal Tests: 131/ 运行 122 的读数在本机无法复核(本机是 Linux,测不到 Windows 的注册条件组合)⇒ 该条保持「未验证」,不因本版重述而变成已验证。
SHA-256
59f00c5984a1495f4b425ca9f5b625d2256be9e8a63769a1cf83afcac60b5ee9 inimerse-0.5.2-Linux-x86_64.deb
92abf97620159662ffeae4b69ce963541a8c2715b4790b0d53ddfde749a993be inimerse-0.5.2-Linux-x86_64.tar.gz
a3dda5e29c715856e0bfc474f6f35c31bee650a9b5191da44ba8a00e4906f83c inimerse-0.5.2-Linux-x86_64.zip