读书笔记 · 约 23,944 字 · 预计推送 3 部分

Rust 所有权与借用:从内存安全到 CLI 工具工程的实际收益(主题精读) 未开始

目录

题记与说明

笔记性质:主题形式精读(非单篇论文)。围绕一个主题检索并深读 6 个来源,按七维提取。
日期:2026-11-03
检索方式:网络可用。全部结论基于本次会话实际抓取到的原文(webReader 全文抓取 + WebSearch 定位),未运行任何代码实验——本主题是文献/工程报告精读,"检查"= 来源原文获取成功,已逐条列在文末执行记录。
与库内已有笔记的关系:2026-10-31-knowledge-4j1kbhrc-4-ripgrep为什么快-*.md 讲的是 ripgrep 的性能机制(正则引擎/并行/内存模型);本篇回答的是另一个问题——所有权与借用这套编译期规则,如何让"内存安全"从运行时事故变成编译期约束,并落到 CLI 工具工程的真实收益上。两篇互补,不重复。

0. 来源总览(6 个,全部读到原文)

#来源类型核心贡献
S1The Rust Book · Ch4.1 What is Ownership?官方教程所有权三条规则、move 语义、drop/RAII、Copy 与 clone 的成本可见性
S2The Rust Book · Ch4.2 References and Borrowing官方教程借用规则、编译期数据竞争排除、悬垂引用编译期拒绝
S3Microsoft MSRC · We need a safer systems programming language (2019-07-18)厂商安全博客~70% CVE 根因是内存安全;三类真实 CVE 解剖(空间/时间/数据竞争)
S4Google Security Blog · Memory Safe Languages in Android 13 (2022-12-01)生产环境实证Android 内存安全漏洞 223→85、76%→35%;Rust 代码零内存安全漏洞
S5Google Security Blog · Safer with Google: Advancing Memory Safety (2024-10-15)策略更新漏洞降到 ~36/年(预测);75% 在野利用的零日是内存安全类;C++ 加固的边界
S6Andrew Gallant · ripgrep is faster than {grep, ag, git grep, ucg, pt, sift} (2016)旗舰 CLI 工具作者的基准报告一个人用 Rust 写出与 GNU grep 同级或更快的并行搜索工具;性能来源是算法+工程+生态库,而非语言本身

一、核心问题:手写内存管理在规模上被证伪

问题的经典表述来自 MSRC(S3):

"the root cause of approximately 70% of security vulnerabilities that Microsoft fixes and assigns a CVE (Common Vulnerabilities and Exposures) are due to memory safety issues. This is despite mitigations including intense code review, training, static analysis, and more."
—— 微软每年修复并分配 CVE 的安全漏洞中,约 70% 的根因是内存安全问题——尽管已有高强度代码评审、培训、静态分析等缓解手段。

Google(S4)给出的行业基线一致:"For more than a decade, memory safety vulnerabilities have consistently represented more than 65% of vulnerabilities across products, and across the industry."(十多年来,内存安全漏洞在各产品、各行业始终占漏洞的 65% 以上。)Google 2024(S5)进一步给出攻击者视角的数据:"Our internal analysis estimates that 75% of CVEs used in zero-day exploits are memory safety vulnerabilities."(Google 内部分析估计,被用于零日漏洞利用的 CVE 中 75% 是内存安全类。)

于是形成了一个"三难":

  1. GC 语言(Java/Go/Python):内存安全,但要付运行时——GC 停顿、内存占用、冷启动,系统级场景(内核、驱动、CLI 冷路径)付不起;
  2. C/C++:无运行时、贴金属,但内存安全靠人;MSRC 的结论是"it is near impossible to write memory-safe code using traditional systems-level programming languages at scale"(用传统系统级语言规模化地写出内存安全的代码几乎不可能,S3);
  3. 工具与流程(sanitizer、fuzzing、评审、培训):十几年没能移动 70% 这个比例(S3 原话:"Tools and guidance are demonstrably not preventing this class of vulnerabilities")。

Rust 的回答是把内存管理变成编译期可判定的规则系统。TRPL(S1)开宗明义:

"Memory is managed through a system of ownership with a set of rules that the compiler checks. If any of the rules are violated, the program won't compile. None of the features of ownership will slow down your program while it's running."
内存通过所有权系统管理,规则由编译器检查;违反任何一条,程序无法编译;所有权的任何特性都不会拖慢程序运行时。

这句话就是整个主题的轴心:把运行时的内存事故搬到编译期,且不引入 GC 式运行时代价。


二、方法:所有权系统到底"搬"了哪些问题

2.1 所有权三条规则与 move 语义 —— 消灭 double free / 泄漏

S1 给出的规则只有三条,简单到可以背下来:

- "Each value in Rust has an owner."
- "There can only be one owner at a time."
- "When the owner goes out of scope, the value will be dropped."

关键机制是 move:let s2 = s1; 对堆上数据(如 String)做的是"浅拷贝 + 使 s1 失效"。TRPL 解释这为什么直接堵死 double free:

"When s2 and s1 go out of scope, they will both try to free the same memory. This is known as a *double free* error... To ensure memory safety, after the line let s2 = s1;, Rust considers s1 as no longer valid."

违反的代码直接编译失败(E0382: borrow of moved value)——错误在编译期以报错形式出现,而不是在用户机器上以崩溃/漏洞形式出现。

配套的确定性析构是 drop(RAII):"Rust calls drop automatically at the closing curly bracket."(S1)。这同时解决了配对问题:"We need to pair exactly one allocate with exactly one free."(S1)——忘释放=泄漏,早释放=悬垂,重释放=漏洞,三条路都被"作用域结束自动 drop + move 转移所有权"这一对机制封死。

2.2 借用 —— "用但不拿",以及编译期数据竞争排除

函数要用值但不想接管所有权时,用引用。S2 的定义值得原样保留:

"We call the action of creating a reference *borrowing*. As in real life, if a person owns something, you can borrow it from them. When you're done, you have to give it back. You don't own it."

引用两条规则(S2 "The Rules of References"):

- "At any given time, you can have *either* one mutable reference *or* any number of immutable references."
- "References must always be valid."

第二条规则("同一时刻要么一个 &mut,要么任意多个 &")的直接推论是数据竞争在编译期被排除。S2 定义数据竞争三条件(两个及以上指针同时访问同一数据、至少一个在写、无同步机制)后说:

"Data races cause undefined behavior and can be difficult to diagnose and fix when you're trying to track them down at runtime; Rust prevents this problem by refusing to compile code with data races!"

悬垂引用同样编译期拒绝(S2):

"In Rust, by contrast, the compiler guarantees that references will never be dangling references: If you have a reference to some data, the compiler will ensure that the data will not go out of scope before the reference to the data does."

还有一个常被忽略的认知设计:成本必须显式。S1:

"When you see a call to clone, you know that some arbitrary code is being executed and that code may be expensive. It's a visual indicator that something different is going on."
以及反方向:"Rust will never automatically create 'deep' copies of your data. Therefore, any *automatic* copying can be assumed to be inexpensive in terms of runtime performance."

即:一切自动发生的拷贝都便宜,一切昂贵的拷贝都写在脸上。这对 CLI 工具意味着性能模型对作者可推理——没有隐藏的 GC 触发、没有隐藏的深拷贝。

2.3 unsafe —— 受控的逃生舱,而非后门

生产环境怎么用 unsafe?S4(Android)给了目前最有说服力的样本:整个 UWB 协议栈

"There are exactly two uses of unsafe in the UWB code... Unsafe was actively helpful in this situation because the extra attention on this code allowed us to discover a possible race condition and guard against it."

unsafe 被用作审查标记:少量、封装、被额外审视——与 MSRC S3 里"C/C++ 全程序都无法静态证明安全"形成对照。S4 的类比:"it has proven significantly simpler to review small snippets of C/C++ for safety than entire programs."


三、数据与证据:从语言规则到生产环境数字

3.1 微软(S3, 2019):问题的解剖

S3 用三个真实 CVE 展示三类内存安全问题,且三个案例的共同根因被点名:

对 UAF 案例的总结(这句是理解借用检查器价值的钥匙):

"The root of the problem comes from aliasing pointers that point to mutable state. C and C++ do not have the tools to enforce the prevention of such errors."
问题的根源是别名指针指向可变状态——而 C/C++ 没有工具能强制阻止这类错误。

注意:这正是 Rust 借用规则直接瞄准的东西——"一个 &mut XOR 多个 &"就是对"别名 × 可变"组合的编译期禁止。S3 还点出工具链的一个结构性困境:Edge 那个越界写修复"easy: move the 'offset check' closer to the time of use",但"The problem is that this is very error-prone in complex code bases and a simple refactor of the code could open this vulnerability again"——没有语言级保证,修复只是把漏洞推后。

3.2 Android(S4, 2022 → S5, 2024):生产环境的因果链证据

这是目前公开的最强自然实验(新代码换语言,旧代码不动):

指标201920222024(预测)
Android 年度内存安全漏洞数22385"a projected 36"(S5 原文 "dropping from more than 220 in 2019 to a projected 36 by the end of this year")
占 Android 总漏洞比例76%35%—(S4)
新原生代码中 Rust 占比—~21%(约 150 万行,S4)—

三个关键引述:

"Android 13 is the first Android release where a majority of new code added to the release is in a memory safe language."(S4)
"To date, there have been zero memory safety vulnerabilities discovered in Android's Rust code."(S4,截至 2022-12,两版 Android 的 Rust 代码)
"Historical vulnerability density is greater than 1/kLOC (1 vulnerability per thousand lines of code) in many of Android's C/C++ components (e.g. media, Bluetooth, NFC, etc). Based on this historical vulnerability density, it's likely that using Rust has already prevented hundreds of vulnerabilities from reaching production."(S4)

严重度同样在降(S4):2022 年内存安全漏洞只占漏洞数的 36%,却占 86% 的 critical 级、89% 的可远程利用级、78% 的在野利用漏洞——"Memory safety vulnerabilities disproportionately represent our most severe vulnerabilities." 所以减少这一类,减掉的是最痛的那部分。Google 2024(S5)确认趋势持续,并把官方立场说透:C++ 加固(MiraclePtr "effectively mitigated 57% of use-after-free vulnerabilities in privileged processes")、边界检查、沙箱都是"Risk Reduction",但——

"While we won't make C and C++ memory safe, we are eliminating sub-classes of vulnerabilities in the code we own."(S5)
—— 我们不会把 C/C++ 变得内存安全,只能消灭其中若干子类漏洞。

即加固是减法且不完备,换语言才是"预防"("we are focused primarily on preventing the introduction of security vulnerabilities at scale", S5)。

必须如实标注的证据边界:S4 作者自己写了"While correlation doesn't necessarily mean causation... Of course there may be other contributing factors or alternative explanations",但同时给出排除项——Android 持续加码的 Scudo/HWASAN/GWP-ASAN/KFENCE 等工具"alone do not account for the large shift",且"other projects that have deployed these technologies have not seen a major shift"。另外,检索摘要中出现过的"76%→24%"说法在我实际读到的 S5 原文中没有逐字出现(S5 原文给的是 >220→36 的绝对数),本笔记不采信该百分比,只用已读到的数字。

3.3 ripgrep(S6, 2016):CLI 工具工程的实证样本

ripgrep 是"Rust CLI 工程"的招牌案例,作者 Andrew Gallant(同时也是底层 regex 引擎作者)用 25 组基准支持三条结论:

"For both searching single files *and* huge directories of files, no other tool obviously stands above ripgrep in either performance or correctness." / "ripgrep is the only tool with proper Unicode support that doesn't make you pay dearly for it." / "Tools that search many files at once are generally *slower* if they use memory maps, not faster."

代表性数字(Linux kernel 树,模式 PM_RESUME):

rg (ignore)  0.334 ± 0.053   ag (ignore) (mmap)  1.588 ± 0.011
git grep     0.345 ± 0.007   pt (ignore)        14.417 ± 0.144  (-w 场景)

单文件 alternation 场景 rg 0.294 vs grep 2.955(约一个数量级);Unicode 词边界场景 rg 无惩罚而 git grep 慢 5 倍。

但要如实摘录作者的反向澄清:S6 全文把性能归因于算法与工程——Teddy SIMD 多模式匹配、"rarest byte" memchr 技巧、最少 stat 调用的目录遍历、RegexSet 批量匹配 .gitignore、增量缓冲区搜索("Thou Shalt Not Search Line By Line")、显式不用 mmap。文中没有"因为 Rust 所以快"的表述;作者的基准自评也很克制:"the benchmarks I'm presenting here are *curated*, and... therefore also *biased*."

Rust 在这个案例里的真实贡献是三件别的事:

  1. 一个人扛住复杂度:并行工作分配复用现成并发原语——"Rust's ecosystem is so great that I was able to reuse a lock-free Chase-Lev work-stealing queue for distributing work to a pool of searchers."(S6)无锁队列这种在 C 里稍写错就是未定义行为的组件,在 Rust 生态里是拿来就用的库。
  2. 优化被库下放:"ripgrep doesn't have to do much of this literal optimization work itself. Most of it is done inside Rust's regex library, so every consumer of that library gets all these performance optimizations automatically!"(S6)——所有权/借用让"高性能零拷贝 API"可以被库安全地封装(把字节缓冲区借给引擎而不交出所有权),于是底层优化写一次、全生态受益。
  3. 同一性能水平上没有内存安全债:S6 列出的增量缓冲区簿记(半行跨界、超长行、上下文跨缓冲区携带)正是 C 实现 grep 类工具时悬垂指针/越界的经典温床;在 Rust 里这些簿记被类型系统强制显式化。(此句为我的推断,S6 原文只说 "it's *hard*" 并列出簿记清单,未讨论 C 的对应漏洞——但 MSRC S3 的三个 CVE 恰好提供了这类簿记出错变成 CVE 的实例。)

CLI 工程收益清单(由 S4+S6 交叉支撑):


四、结论

  1. 所有权与借用的本质:用"单一所有者 + 借用互斥(一个 &mut XOR 多个 &)+ 引用必须有效"三条编译期规则,把 double free、悬垂指针、数据竞争——即 C/C++ 约 70% 漏洞的根因(别名指向可变状态)——从运行时搬到编译期,且运行时零开销(S1/S2/S3)。
  2. 生产证据成立:Android 是公开可查的最大规模验证——新代码换 Rust 后,内存安全漏洞从 223/年(76%)降到 85/年(35%,2022),2024 预测降至 ~36;Android 的 Rust 代码截至 2022-12 零内存安全漏洞(S4/S5)。
  3. 对 CLI 工程,收益是"工程的"而非"性能玄学的":ripgrep 的快来自算法与工程,不是语言魔法;语言给的收益是——无运行时的单二进制分发、编译期并行安全、昂贵操作显式化、优化经库全生态复用(S6/S4/S1)。
  4. 换语言的正确姿势是"新代码"而非"重写":Android 策略明确 "our goal is not to convert existing C/C++ to Rust, but rather to shift development of new code to memory safe languages over time"(S4)。

五、局限

  1. 学习曲线是真实成本:TRPL 自己承认 "it does take some time to get used to"(S1);生命周期标注(Ch10)、自引用结构等问题在本笔记读的两节里只露了头(E0106 报错引出了 lifetimes),未展开。
  2. 因果性保留:Android 的数字是相关性+排除法论证(S4 作者明示 correlation ≠ causation),非受控实验。
  3. 统计口径争议未处理:"70%" 的分母(哪些 CVE 算内存安全)存在方法论讨论;本次检索中见到有批判性分析文章(safeguard.sh,出现在搜索结果中)但未读原文,无法评估其论点,如实标注。
  4. MSRC 系列的读法限制:微软站点改版后,我读到的这篇(署名 Ryan Levick & Sebastian Fernandez,2019-07-18)是以"In our first post... we discussed"开头的系列第二篇口径;含 70% 图表的首篇(据称作者为 Matt Miller)我没有直接读到,70% 数字是从这篇的转述句("As was pointed out in our previous post...")引用的。
  5. 巨头数据 vs 个人场景的外推:Android/Edge 的漏洞统计来自数千万行代码、高对抗环境;个人 CLI 工具的收益更多体现为工程体验(单二进制、重构不怕、并行敢写),而不是漏洞数的显著下降。
  6. ripgrep 案例的时间性:S6 是 2016 年 v0.1.2 的基准,ripgrep 与 regex 引擎此后大改版;本笔记只引用其工程方法论层面的结论,具体毫秒数已过时。
  7. 未验证项:本笔记未编译/运行任何 Rust 代码复现 E0382/E0499/E0502/E0106 报错(报错文本引自 TRPL 原文);未复现 ripgrep 基准。

六、七维提取

1. 核心问题

如何在不需要 GC 运行时的前提下获得内存安全?——更准确地说:C/C++ 十几年证明"工具+流程"压不住约 70% 的内存安全 CVE(S3),GC 语言又付不起系统级/CLI 场景的运行时代价;Rust 的所有权与借用系统试图用编译期规则同时满足"安全"与"无运行时"。

2. 主要主张

3. 方法

4. 数据与证据

充分性评估:语义与实证两层互相咬合、可信度高;CLI 工程层证据充分但偏老(2016),且"Rust→快"的因果被作者本人明确拒绝——这是诚实的数据。

5. 结论

所有权/借用把"别名指向可变状态"这一漏洞总根因变成编译错误;Android 六年数据是迄今最强的生产级验证;对 CLI 工具,实际收益=安全基线免费获得+工程性质变(单二进制、敢并行、敢重构、成本可见),性能本身仍靠算法与工程。

6. 局限

见第五节:学习曲线、相关性非因果、70% 口径争议、MSRC 首篇未直接读到、巨头数据外推边界、ripgrep 基准时效、未做本地代码复现。

7. 对我的启发


七、重要原文引述索引(防丢失)

S1 — TRPL Ch4.1(https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html)

S2 — TRPL Ch4.2(https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html)

S3 — MSRC(https://www.microsoft.com/en-us/msrc/blog/2019/07/we-need-a-safer-systems-programming-language,Ryan Levick & Sebastian Fernandez,2019-07-18)

S4 — Google Security Blog(https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html,Jeff Vander Stoep,2022-12-01)

S5 — Google Security Blog(https://security.googleblog.com/2024/10/safer-with-google-advancing-memory.html,Alex Rebert, Chandler Carruth, Jen Engel, Andy Qin,2024-10-15)

S6 — Andrew Gallant / burntsushi(https://blog.burntsushi.net/ripgrep/,2016-09)


八、本会话执行记录(可复现)

1. ls D:/CodexData/nightshift/output/knowledge/notes/        → 确认目录与命名规范
2. WebSearch ×3:
   a. Rust ownership borrowing chapter The Rust Programming Language  → 定位 TRPL Ch4
   b. burntsushi ripgrep blog ...                                      → 定位 S6
   c. "We need a safer systems programming language" 70% / Google 2024  → 定位 S3 新 URL 与 S5
3. webReader 全文抓取成功(6/6 有效来源):
   - https://doc.rust-lang.org/book/ch04-01-what-is-ownership.html
   - https://doc.rust-lang.org/book/ch04-02-references-and-borrowing.html
   - https://security.googleblog.com/2022/12/memory-safe-languages-in-android-13.html
   - https://blog.burntsushi.net/ripgrep/
   - https://www.microsoft.com/en-us/msrc/blog/2019/07/we-need-a-safer-systems-programming-language
   - https://security.googleblog.com/2024/10/safer-with-google-advancing-memory.html
4. 失败与绕行:
   - webReader 抓 MSRC 旧 URL(msrc.microsoft.com/blog/2019/07/...)→ 500 网络错误;
     WebFetch 该 URL → 301 重定向至博客首页;改用 www.microsoft.com 全路径成功。
   - WebFetch security.googleblog.com/2024/09/eliminating-memory-safety-vulnerabilities.html → 连接超时;
     检索发现目标实为 2024-10-15 的 "Safer with Google" 帖,抓取成功。
5. grep 已有笔记 2026-10-31-knowledge-4j1kbhrc-4-ripgrep为什么快-*.md 的标题结构(只读)→ 确认角度不重复。
6. 未做:未编译/运行 Rust 代码复现编译错误,未复现 ripgrep 基准(文献精读,非实验主题)。
← 资料库今日播报 →