oven-sh/bun at f91d5c95 · static read-only analysis · why-not-rust method 2.0oven-sh/bun 于 f91d5c95 · 只读静态分析 · why-not-rust method 2.0
Repository: github.com/oven-sh/bun at commit f91d5c95, shallow clone, 19,034 tracked files. Scope: the whole repository, with the ported host-runtime layer as the assessed target. Sampling: 1,008,327 lines of Rust across 1,496 files, 1,005,761 of them under src/; zero .zig files and no build.zig; Cargo.toml present; 311,915 lines of C across 122 files, 290,842 of C++ across 605 files, 105,026 of headers across 808 files, and 825,147 of TypeScript across 3,073 files. Unsafe surface was counted by pattern across tracked .rs files: 10,257 opening unsafe blocks, 1,235 unsafe fn, 399 unsafe impl, 966 unsafe extern, with 751 of 1,496 files (50.2%) containing at least one of those four forms. A bare substring search returns 786 instead; it also matches identifiers such as unsafe_code and prose in comments, so the narrower four-form count is the one reported. Derived: roughly one opening unsafe block per 98 lines of Rust (1,008,327 / 10,257 = 98.3). No build, test, benchmark or network call was run against the project, and deleted history was not inspected, so the roughly 535,496-line pre-port Zig figure is the first-party one from https://bun.com/blog/bun-in-rust rather than a measurement taken here. Objective: eliminate the recurring use-after-free, double-free and leak class without regressing shipped performance or JavaScript-facing behaviour. User-supplied facts: none. Amdahl inputs, in baseline-time units: share=1.00 because the whole program is the candidate kernel, kernel speedup=1.048 from the best selected first-party figure (Bun.serve +4.8%), boundary=0, target=1.5 → end-to-end 1.048x, infinite-kernel ceiling unbounded, target physically possible and NOT met by the candidate. Read that pair carefully. With the whole program as the kernel there is no Amdahl wall at all, so the wall is empirical: the measured native-to-native delta of 4.8% at best. On the speed axis this same migration fails gate 3; on the safety axis it passes. The axis decides it, not the scope. Why the selected option is the smallest sufficient step: the defect class is a property of manual lifetime management throughout the runtime rather than of one component behind an interface. No extraction reaches it. A module-by-module port would pay a Zig-Rust boundary for years while leaving the requirement unmet in the unported remainder. Evidence gaps and their effect: no post-port measurement of the target defect class has been published, which holds confidence at MEDIUM and robustness at CONDITIONAL; the 10,257 opening unsafe blocks are unclassified, so residual unsafety is unquantified; and the benchmark figures are vendor-selected. A third-party account contested the port's production-readiness at publication (https://www.theregister.com/devops/2026/07/14/zig-creator-calls-buns-claude-rust-rewrite-unreviewed-slop/5270743); it is recorded as a contested-quality signal in neutral terms, with no claim about anyone's motives. Line counts across languages are not treated as comparable measures of effort or quality: 1,008,327 lines of Rust replacing roughly 535,496 of Zig is a ratio, not a verdict. The framework compares explicit options through four non-compensatory gates and is a structured decision protocol, not a statistical predictor.仓库:github.com/oven-sh/bun,commit f91d5c95,shallow clone,19,034 个受管理文件。范围:整个仓库,被评估的目标是已迁移的宿主运行时层。采样:1,008,327 行 Rust,分布在 1,496 个文件中,其中 1,005,761 行在 src/ 下;0 个 .zig 文件,没有 build.zig;Cargo.toml 存在;311,915 行 C 分布在 122 个文件,290,842 行 C++ 分布在 605 个文件,105,026 行头文件分布在 808 个文件,825,147 行 TypeScript 分布在 3,073 个文件。unsafe 面通过模式匹配在受管理的 .rs 文件上统计:10,257 个 unsafe 起始块、1,235 个 unsafe fn、399 个 unsafe impl、966 个 unsafe extern,1,496 个文件里有 751 个(50.2%)至少含这四种形式之一。直接做子串搜索会得到 786,那个数字还会命中 unsafe_code 之类的标识符和注释里的文字,所以报告采用范围更窄的四形式计数。推导:约每 98 行 Rust 一个 unsafe 起始块(1,008,327 / 10,257 = 98.3)。没有对项目跑过任何 build、test、benchmark 或网络调用,也没有查被删除的历史,所以迁移前约 535,496 行 Zig 这个数字来自 first-party 的 https://bun.com/blog/bun-in-rust,不是在这里测出来的。目标:消除反复出现的 use-after-free、double-free、内存泄漏这一类缺陷,同时不让已发布的性能和面向 JavaScript 的行为退化。用户提供的事实:无。Amdahl 输入,单位为基线时间:share=1.00,因为候选内核就是整个程序;kernel speedup=1.048,取自厂商自选数字里最好的一个(Bun.serve +4.8%);boundary=0;target=1.5 → 端到端 1.048x,无限内核上限 unbounded,目标物理可达,但候选方案 NOT met。这一对要一起读。内核取整个程序时根本没有 Amdahl 墙,所以墙是经验性的:实测的原生到原生差值,最好也就 4.8%。走速度这条轴,同一次迁移过不了 gate 3;走安全那条轴,它过。决定结果的是轴,不是范围。为什么选定方案是最小充分步骤:这一类缺陷是手动生命周期管理贯穿整个运行时的产物,不是接口后面某个组件的产物。抽取够不着它。而逐模块迁移要为 Zig-Rust 边界付上好几年,同时让需求在尚未迁移的部分里一直落空。证据缺口及其影响:迁移后目标缺陷类的测量没有公布过,这把 confidence 钉在 MEDIUM,把 robustness 钉在 CONDITIONAL;10,257 个 unsafe 起始块尚未分类,残余不安全面没有量化;基准数字由厂商自选。发布时有第三方报道质疑了这次迁移的生产就绪度(https://www.theregister.com/devops/2026/07/14/zig-creator-calls-buns-claude-rust-rewrite-unreviewed-slop/5270743),这里以中性措辞记为质量存争议的信号,不对任何人的动机作判断。跨语言的行数不被当作可比的工作量或质量度量:1,008,327 行 Rust 替掉约 535,496 行 Zig,这是一个比例,不是一个结论。本框架把明确列出的方案放进四道非补偿性的门里比较,它是一套结构化决策协议,不是统计预测器。
| What we don't know证据缺口 | What it would change会改变什么 |
| Post-port incidence of the target defect class迁移后目标缺陷类的发生率 | The entire decision rests on this measurement, and no one has published it. Its absence holds confidence at MEDIUM and robustness at CONDITIONAL. It does not change the selected scope. It decides whether anyone can claim the migration worked.整个决策就压在这项测量上,而没有人公布过。它的缺席把 confidence 钉在 MEDIUM,把 robustness 钉在 CONDITIONAL。它不改变选定的范围。它决定「这次迁移奏效了」这句话能不能说。 |
| Classification and encapsulation of the 10,257 unsafe blocks10,257 个 unsafe 块的分类与封装 | Block count is a coarse proxy for risk. Without a split into FFI boundary, engine embedding and performance-critical clusters, each with a documented invariant, the residual unsafety of the selected option stays unquantified.块数是衡量风险的粗糙代理。不把它们拆成 FFI 边界、引擎嵌入、性能关键几簇,并且每簇配一条成文不变量,选定方案的残余不安全面就一直没有量化。 |
| An independent same-workload benchmark一次同负载的独立基准 | The 2.2–4.8% figures are vendor-selected first-party runs. An independent comparison would firm up the parity reading in both directions. This is the report's main quantitative performance claim, and nobody outside the vendor has checked it.2.2–4.8% 这些数字是厂商自选的 first-party 跑分。一次独立对比可以在两个方向上把「持平」这个判断坐实。这是报告里主要的量化性能主张,而厂商之外没有人核过它。 |