<!-- title: 比随机更聪明：模糊测试如何挖出Bug -->
<!-- domain: programming -->
<!-- video: https://www.youtube.com/watch?v=kaD54VXxGrI -->

# 比随机更聪明：模糊测试如何挖出 Bug

## 导语：让程序自己"招供"

每一个写代码的人都活在一种焦虑里——我到底漏掉了什么？单元测试覆盖了你想到的分支，集成测试覆盖了你设计好的路径，可真正的灾难几乎永远藏在你**想不到的角落**：一个谁也没预料到的输入、一个极端的边界值、一段并发竞争。2014 年的 Heartbleed，一行 `memcpy` 漏了长度检查，让全球近两成 HTTPS 服务器心脏裸奔；类似的"一行代码"级缺陷，在 C/C++、Rust、Go、Java 的世界里每天都在被悄悄制造。

Computerphile 在 2026 年 6 月 4 日发布的这期《Fuzzing Programs to Find Bugs》请来的不是泛泛而谈的科普嘉宾，而是帝国理工学院（Imperial College London）**Multicore Programming 研究组**的掌门人 **Alastair F. Donaldson 教授**——一个真正靠"让程序吃垃圾输入、再观察它怎么死"吃饭的学者。视频一句话点题：模糊测试（Fuzzing）就是用随机输入去喂程序找 bug，但**真正强大的，是比随机更聪明的办法**。这篇文章，我会把视频的核心拆开，再补上它没来得及展开的硬核背景：覆盖率引导、变异与生成、sanitizer、以及 Donaldson 本人最拿手的"蜕变测试"（metamorphic testing）——专门对付那些连"对错都没法判断"的诡异程序。

## 视频背景卡片

| 项目 | 内容 |
|------|------|
| 视频标题 | Fuzzing Programs to Find Bugs |
| 频道 | Computerphile（约 270 万订阅） |
| 出镜专家 | Prof. Alastair F. Donaldson，帝国理工学院 Multicore Programming 研究组 |
| 发布日期 | 2026-06-04 |
| 时长 | 典型 Computerphile 篇幅（约 10–13 分钟） |
| 核心主题 | 用随机输入找 bug，以及比随机更聪明的模糊测试方法 |
| 配套背景 | Computerphile 由 Jane Street 赞助，Sean Riley 拍摄剪辑 |

## 核心内容拆解

### 1. 模糊测试到底是什么：让程序替你"试错"

视频的开场定义干脆利落：Fuzzing 就是一种**通过给程序灌入大量、往往是随机的输入，来触发并暴露编程缺陷**的技术。它的哲学和传统测试截然相反——传统测试是"我想到了这种用法，验证它对"，而 fuzzing 是"我压根不想，让机器去穷尽、去碰撞，看哪里会炸"。

这个词诞生于 1988 年威斯康星大学麦迪逊分校的 **Barton Miller** 教授课堂项目。他的团队当时往 UNIX 命令行工具里狂塞随机字节流，结果惊人：当时主流的工具，**将近三分之一都会崩溃或挂起**。三十多年过去，"fuzz"这个词沿用至今，而当年那个粗糙的课堂实验，已经长成了现代软件安全最重要的支柱之一。需要说明，视频只点到了"随机输入"这层皮；这段历史是我补充的背景，帮你理解这门技术不是新玩具，而是久经考验的老兵。

### 2. 朴素随机的致命短板：针在上了锁的保险箱里

Donaldson 在视频里点破了一个关键认知：纯随机输入**听起来暴力有效，实际上效率低得可怜**。原因很反直觉——绝大多数随机数据，会在程序的**入口处**就被防御性代码弹回来。一个 JSON 解析器，你喂它一堆乱码，它在第一个字符就报"格式错误"返回了，根本走不到后面几百行的状态机逻辑。

打个比方：你想在保险箱里找一根针，可你连保险箱的门都打不开。纯随机 fuzzing 就是站在门外乱扔石子。程序的深层逻辑——那些真正藏 bug 的状态机分支——被层层输入校验保护着，随机输入的"穿透率"极低。这就是为什么"更聪明的办法"不是锦上添花，而是**从玩具变成武器**的分水岭。视频的核心论点，正在于此。

### 3. 覆盖率引导：AFL 与 libFuzzer 的"进化论"魔法

这是"更聪明"的核心一跃，也是我最想为你讲透的一点。现代覆盖率引导型 fuzzer（以 **AFL**、**libFuzzer** 为代表）的工作方式，活脱脱是一场**遗传算法式的达尔文进化**：

它先给你一批"种子输入"（seed corpus，通常是几个合法的样本文件），运行被测程序，同时插桩统计**这次输入走过了哪些代码分支**。然后它不断"变异"这些输入——位翻转（bit-flip）、字节增删、插入特殊符号、查"字典"里的高频 token——只要某个变异后代**触发了之前没走到的新分支**，就把它"留下来"当新的父本，继续繁衍；触不到新代码的后代则被淘汰。

这套"**覆盖率当适应度函数、变异当基因操作、保留有效后代**"的闭环，让 fuzzer 像有了嗅觉一样，**主动朝未覆盖的代码区域探索**。结果是：它能在数小时内钻透那些纯随机穷举几千年都碰不到的深层状态。AFL 的作者 Michał Zalewski 当年用它在几十个主流开源项目里挖出上千个 bug，一战封神。视频限于篇幅只是"暗示"了"更聪明"，我把这套机制给你讲明白——因为这是你真正能用上的东西。

### 4. 变异 vs 生成：结构化输入要"懂语法"

但光靠 bit-flip 还不够。当被测程序吃的是**高度结构化**的输入——比如编译器吃的源代码、协议解析器吃的二进制报文、浏览器吃的 HTML——盲目变异几乎必然在语法层面就被拒之门外。于是 fuzzer 分出两条进化路线：

**变异型**（mutation-based）：AFL/libFuzzer 的基本盘，对种子做原子级扰动，配上"字典"（比如 SQL 解析器就喂 `SELECT`、`UNION`、`'` 这些 token）大幅提升穿透力。**生成型**（generation-based / grammar-aware）：直接用**语法规则**去合成合法输入，比如照着 JSON 文法、或协议 RFC 的字段布局去构造，保证输入能通过初筛，再在合法的骨架上做"语义层面"的破坏。后者尤其适合测试协议栈、数据库引擎、编译器这类"输入高度规整"的目标。这是视频之外、但理解 fuzzing 全貌绕不开的一环。

### 5. Oracle 难题：你怎么知道"它错了"？

这是 Donaldson 整个研究生涯的核心战场，也是视频一定会触及却未必能在一期里讲透的深层问题。Fuzzing 喂进输入、程序跑了，**然后呢？你怎么判定这次执行是"对的"还是"错的"？** 这个判定标准，学术界叫 **oracle（神谕）**。

最省事的 oracle 是**崩溃**：程序 segfault、除零、assert 失败、内存越界——它自己"喊疼"了，那肯定是 bug。绝大多数工业 fuzzing 就靠这个。可问题在于，**大量致命缺陷根本不崩溃**：一块内存被悄悄多读了 64 字节（Heartbleed 就是这种）、一个浮点结果悄悄错了、一个编译器把语义正确的程序悄悄优化错了——程序"看起来"跑完了，但结果是错的。崩溃抓不到它们。

工业界的第一道补丁是 **sanitizer**（消毒器）：编译时给程序插上"探针"，把那些"不崩溃但非法"的行为——释放后使用、缓冲区越界、未定义行为、未初始化内存——**放大成可见的崩溃**。Google 的 **AddressSanitizer（ASan）**、UndefinedBehaviorSanitizer（UBSan）、MemorySanitizer（MSan）是这一派的代表，几乎和 fuzzer 形影不离。但 sanitizer 也有抓不到的盲区，这就引出了 Donaldson 的看家本领。

### 6. 蜕变测试：当连"正确答案"都不存在

Donaldson 领导的 Multicore Programming 研究组，常年面对的是这个星球上**最难判定对错**的程序——GPU 着色器（shader）、并行程序、编译器优化器。它们的共同特点是：**你压根没有一个"标准答案"可以对照**。

一个 shader 把三角形渲染成某种颜色，谁来告诉你正确颜色是啥？一个编译器把循环优化了 5 倍，输出二进制不一样了，谁来判断它"语义没变"？这种"无 oracle"领域，崩溃抓不到、sanitizer 也无能为力，因为程序**优雅地输出了一个错误结果，却没人能说它是错的**。

Donaldson 的武器是**蜕变测试（Metamorphic Testing）**：既然拿不到绝对答案，那就找**输入之间的"等价关系"**。比如：把图像先放大再缩小，结果应该接近原图（顺序无关）；把着色器的循环展开 2 倍，渲染结果应当像素级一致；把同一份代码用两种优化等级编译，运行输出应当相同。这些"如果 A 成立，那 B 必然也成立"的**蜕变关系**，本身就是一把隐形的尺子——一旦程序在某个变换下破坏了这种关系，就说明它出 bug 了，哪怕它一个字节都没崩。

Donaldson 团队据此打造了著名的 **GraphicsFuzz**——专门用蜕变测试猎杀 GPU 驱动和着色器编译器里的深层缺陷。这套工具后来被华为收购，成为工业级 GPU 测试的基石。这是我个人认为**视频里最值钱、又最容易被普通观众一耳朵划过去**的部分，所以我特意拎出来重点讲：当你的程序"没有标准答案"时，蜕变测试是几乎唯一通用的破局之道。

### 7. 实战战果：Fuzzing 真的改变了软件安全

如果你觉得上面像学术清谈，那看看战果。**Google 的 OSS-Fuzz**（2016 年启动）把覆盖率引导 fuzzing 直接做成了公共服务：每天对上千个关键开源项目（从 LLVM、SQLite 到 FFMpeg、OpenSSL）持续狂轰，截至近年累计挖出**三万多个**真实 bug，其中上千个是高危安全漏洞。它底层同时用 libFuzzer、AFL++ 和 Honggfuzz，再叠加 sanitizer 三重奏。

再比如 Chromium 浏览器，每年靠 fuzzing 抓掉的渲染引擎、V8 引擎缺陷数以千计；微软的 **Project OneFuzz** 把同样的思路搬上了 Azure 云；Rust、Go（1.18 起内置原生 fuzzing）、Java（Jazzer）几乎所有主流语言现在都把 fuzzing 当一等公民内置进工具链。可以说，**今天任何一个严肃的基础软件，如果没接 CI 持续 fuzzing，几乎是裸奔**。视频作为科普没列这些数字，但补上它们，你才能掂量出 Donaldson 谈的"更聪明"到底有多值钱。

### 8. 把 Fuzzing 塞进你的开发流：从"高级技巧"到"日常习惯"

最后一层，是如何落地。现代 fuzzing 早就不是安全研究员的专利，而是普通开发者的**日常习惯**。核心套路是三步：第一，写一个极简的 **fuzz target**——一个 `LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)` 函数，把随机字节喂给你的被测函数；第二，**开 sanitizer 编译**（`-fsanitize=address,fuzzer`），让隐藏缺陷显形；第三，把它挂进 CI，**持续跑**——每天用积累的语料库不断挖掘新路径。

工具选择上：C/C++ 用 **libFuzzer** 或 **AFL++**，Java 用 **Jazzer**，Go 用 1.18+ 的原生 `go test -fuzz`，Python 用 **Atheris**，协议/结构化输入用 grammar fuzzer。门槛已经低到一个下午就能给项目的关键解析器配上。Donaldson 视频的价值，正在于它把这门"听起来很黑魔法"的技术，还原成了人人能上手的工程实践。

## 知识结构图

```mermaid
flowchart TD
  A["被测程序<br/>Program Under Test"] --> B{"Fuzzing 模糊测试"}

  B --> C["输入生成"]
  C --> C1["随机生成 Random<br/>门槛低·穿透率低"]
  C --> C2["变异 Mutation<br/>基于种子语料库"]
  C --> C3["结构感知 Generation<br/>语法/协议驱动"]

  B --> D["执行 + 监控"]
  D --> D1["代码覆盖率反馈<br/>AFL / libFuzzer"]
  D --> D2["Oracle 判定对错"]

  D2 --> D2a["崩溃 Crash<br/>最省事"]
  D2 --> D2b["Sanitizer 放大缺陷<br/>ASan / UBSan / MSan"]
  D2 --> D2c["蜕变测试 Metamorphic<br/>无标准答案时<br/>Donaldson 的专长"]

  D1 -->|"保留走新路径的输入"| C2
  D2 -->|"触发缺陷"| E["Bug 报告 + 复现用例"]
  E --> F["CI/CD 持续模糊<br/>OSS-Fuzz / OneFuzz / CIFuzz"]
```

## 实战启示：开发者该立刻做点什么

看完这期视频和上面的拆解，如果你只记三句话，那就是：

**第一，给"吃外部输入的代码"配 fuzz target。** 解析器、协议解码器、文件格式读取、反序列化——凡是接收不可信输入的边界函数，都是 fuzzing 的高价值靶子。写一个十几行的 fuzz target，给 libFuzzer/AFL++ 跑一夜，你大概率会被它在深层状态机里挖出的崩溃惊到。这是性价比最高的起步动作。

**第二，永远开 sanitizer 构建。** 你不需要为了用 sanitizer 而用 fuzzer；反过来，sanitizer 单独开（`-fsanitize=address,undefined`）就能在日常测试里抓出大量"不崩溃的内存 bug"。把它加进你的 debug build 和 CI，几乎零成本换来一道硬核防线。

**第三，遇到"无法判断对错"的程序，想想蜕变关系。** 这是我从 Donaldson 身上借来的最值钱的方法论：当你发现一段代码（渲染、数值计算、编译优化、并发）连"正确输出"都定义不清、写不出断言时，别放弃测试——去找**输入之间的等价关系**（顺序无关、幂等、双射可逆、规模可分解……），把它变成自动化的蜕变检查。这往往是这类"难测程序"唯一的系统性测试出路。

认知升级层面，fuzzing 给我们上了一课：**人类擅长构造"应该通过"的用例，机器擅长穷举"应该失败"的角落**。把这两者结合，把测试从"证明我想对了"扩展成"机器帮我找漏"，才是现代软件质量管理的完整图景。Donaldson 这期视频最大的价值，恰恰是它把这门技术从"安全研究员的高墙"里请了出来，放回了每个开发者的工具箱。

## 延伸学习路径

1. **The Fuzzing Book**（fuzzingbook.org）——萨尔大学 Andreas Zeller 等人撰写的免费在线教科书，可直接运行的 Python 笔记，从随机测试讲到覆盖率引导再到语法 fuzzing，是目前最好的系统入门。
2. **OSS-Fuzz**（google.github.io/oss-fuzz）——Google 的持续 fuzzing 平台，可以读它公开的数千个真实 bug 报告，感受工业级 fuzzing 的威力。
3. **AFL++**（GitHub: AFLplusplus/AFLplusplus）——AFL 的社区增强版，是当下最活跃的开源覆盖率引导 fuzzer，README 本身就是一篇优秀教程。
4. **Barton Miller 经典 Fuzz 项目页**（pages.cs.wisc.edu/~bart/fuzz/）——回到 1988 年的源头，看看这门技术最初是怎么诞生的，对比三十年进化。
5. **Donaldson 团队的 GraphicsFuzz 与蜕变测试论文**——想深入"无 oracle 测试"，去 Imperial College 他的研究组主页追相关论文，这是视频背后真正硬核的学术根基。

## 一句话总结

模糊测试的真正威力，不在于"随机砸"，而在于**用覆盖率当罗盘、用 sanitizer 放大破绽、用蜕变关系攻克无解之域**——把"找 bug"这件靠运气的事，变成了一台可工程化的、24 小时不眠的猎虫机器。

## 参考来源

1. [Fuzzing Programs to Find Bugs — Computerphile](https://www.youtube.com/watch?v=kaD54VXxGrI) — 本文分析的核心视频（专家：Prof. Alastair F. Donaldson，Imperial College London）
2. [Barton Miller — Fuzz 项目（威斯康星大学）](https://pages.cs.wisc.edu/~bart/fuzz/) — Fuzzing 概念的 1988 年发源地与原始论文
3. [The Fuzzing Book](https://www.fuzzingbook.org/) — Andreas Zeller 等著的免费在线教科书，系统讲解模糊测试
4. [Google OSS-Fuzz](https://google.github.io/oss-fuzz/) — 持续 fuzzing 平台，累计挖出三万多个开源项目缺陷
5. [AFLplusplus/AFLplusplus (GitHub)](https://github.com/AFLplusplus/AFLplusplus) — 覆盖率引导模糊测试的主力开源工具

---
> 本文由「51学通信」技术团队出品。51学通信由通信行业18年老兵**爱卫生**（微信ID: gprshome201101）维护，聚焦5G/6G核心网、3GPP标准解读、通信前沿技术深度分析。
> 出版作品有《5G核心网原理与实践》《IMS原理与实践》等4本通信专业书籍。知识星球「51学通信」提供深度技术答疑和行业洞察。

> [!tip] 51学通信知识星球
> **星主：爱卫生**（微信：gprshome201101）——公众号「51学通信」创办者，19 年通信行业运维与讲师经验，著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书（各大电商平台有售）。
> **星球定位**：深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域，主打运维岗位与信令分析。
> **当前规模**：5200 篇主题 / 990 个回答，198 元/年。
> **加入福利**：加入星球后请加爱卫生微信，拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题，另有群内分享。
> **AI 加持**：51学通信知识星球已作为 skill 接入 WorkBuddy，使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例，做总结、找文档和 PPT 等场景全覆盖。

![51学通信知识星球海报-扫码加入](https://wiki.500nian.com/images/zhixingqiu_qrcode.png)
