每一个写代码的人都活在一种焦虑里——我到底漏掉了什么?单元测试覆盖了你想到的分支,集成测试覆盖了你设计好的路径,可真正的灾难几乎永远藏在你想不到的角落:一个谁也没预料到的输入、一个极端的边界值、一段并发竞争。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 拍摄剪辑 |
视频的开场定义干脆利落:Fuzzing 就是一种通过给程序灌入大量、往往是随机的输入,来触发并暴露编程缺陷的技术。它的哲学和传统测试截然相反——传统测试是"我想到了这种用法,验证它对",而 fuzzing 是"我压根不想,让机器去穷尽、去碰撞,看哪里会炸"。
这个词诞生于 1988 年威斯康星大学麦迪逊分校的 Barton Miller 教授课堂项目。他的团队当时往 UNIX 命令行工具里狂塞随机字节流,结果惊人:当时主流的工具,将近三分之一都会崩溃或挂起。三十多年过去,"fuzz"这个词沿用至今,而当年那个粗糙的课堂实验,已经长成了现代软件安全最重要的支柱之一。需要说明,视频只点到了"随机输入"这层皮;这段历史是我补充的背景,帮你理解这门技术不是新玩具,而是久经考验的老兵。
Donaldson 在视频里点破了一个关键认知:纯随机输入听起来暴力有效,实际上效率低得可怜。原因很反直觉——绝大多数随机数据,会在程序的入口处就被防御性代码弹回来。一个 JSON 解析器,你喂它一堆乱码,它在第一个字符就报"格式错误"返回了,根本走不到后面几百行的状态机逻辑。
打个比方:你想在保险箱里找一根针,可你连保险箱的门都打不开。纯随机 fuzzing 就是站在门外乱扔石子。程序的深层逻辑——那些真正藏 bug 的状态机分支——被层层输入校验保护着,随机输入的"穿透率"极低。这就是为什么"更聪明的办法"不是锦上添花,而是从玩具变成武器的分水岭。视频的核心论点,正在于此。
这是"更聪明"的核心一跃,也是我最想为你讲透的一点。现代覆盖率引导型 fuzzer(以 AFL、libFuzzer 为代表)的工作方式,活脱脱是一场遗传算法式的达尔文进化:
它先给你一批"种子输入"(seed corpus,通常是几个合法的样本文件),运行被测程序,同时插桩统计这次输入走过了哪些代码分支。然后它不断"变异"这些输入——位翻转(bit-flip)、字节增删、插入特殊符号、查"字典"里的高频 token——只要某个变异后代触发了之前没走到的新分支,就把它"留下来"当新的父本,继续繁衍;触不到新代码的后代则被淘汰。
这套"覆盖率当适应度函数、变异当基因操作、保留有效后代"的闭环,让 fuzzer 像有了嗅觉一样,主动朝未覆盖的代码区域探索。结果是:它能在数小时内钻透那些纯随机穷举几千年都碰不到的深层状态。AFL 的作者 Michał Zalewski 当年用它在几十个主流开源项目里挖出上千个 bug,一战封神。视频限于篇幅只是"暗示"了"更聪明",我把这套机制给你讲明白——因为这是你真正能用上的东西。
但光靠 bit-flip 还不够。当被测程序吃的是高度结构化的输入——比如编译器吃的源代码、协议解析器吃的二进制报文、浏览器吃的 HTML——盲目变异几乎必然在语法层面就被拒之门外。于是 fuzzer 分出两条进化路线:
变异型(mutation-based):AFL/libFuzzer 的基本盘,对种子做原子级扰动,配上"字典"(比如 SQL 解析器就喂 SELECT、UNION、' 这些 token)大幅提升穿透力。生成型(generation-based / grammar-aware):直接用语法规则去合成合法输入,比如照着 JSON 文法、或协议 RFC 的字段布局去构造,保证输入能通过初筛,再在合法的骨架上做"语义层面"的破坏。后者尤其适合测试协议栈、数据库引擎、编译器这类"输入高度规整"的目标。这是视频之外、但理解 fuzzing 全貌绕不开的一环。
这是 Donaldson 整个研究生涯的核心战场,也是视频一定会触及却未必能在一期里讲透的深层问题。Fuzzing 喂进输入、程序跑了,然后呢?你怎么判定这次执行是"对的"还是"错的"? 这个判定标准,学术界叫 oracle(神谕)。
最省事的 oracle 是崩溃:程序 segfault、除零、assert 失败、内存越界——它自己"喊疼"了,那肯定是 bug。绝大多数工业 fuzzing 就靠这个。可问题在于,大量致命缺陷根本不崩溃:一块内存被悄悄多读了 64 字节(Heartbleed 就是这种)、一个浮点结果悄悄错了、一个编译器把语义正确的程序悄悄优化错了——程序"看起来"跑完了,但结果是错的。崩溃抓不到它们。
工业界的第一道补丁是 sanitizer(消毒器):编译时给程序插上"探针",把那些"不崩溃但非法"的行为——释放后使用、缓冲区越界、未定义行为、未初始化内存——放大成可见的崩溃。Google 的 AddressSanitizer(ASan)、UndefinedBehaviorSanitizer(UBSan)、MemorySanitizer(MSan)是这一派的代表,几乎和 fuzzer 形影不离。但 sanitizer 也有抓不到的盲区,这就引出了 Donaldson 的看家本领。
Donaldson 领导的 Multicore Programming 研究组,常年面对的是这个星球上最难判定对错的程序——GPU 着色器(shader)、并行程序、编译器优化器。它们的共同特点是:你压根没有一个"标准答案"可以对照。
一个 shader 把三角形渲染成某种颜色,谁来告诉你正确颜色是啥?一个编译器把循环优化了 5 倍,输出二进制不一样了,谁来判断它"语义没变"?这种"无 oracle"领域,崩溃抓不到、sanitizer 也无能为力,因为程序优雅地输出了一个错误结果,却没人能说它是错的。
Donaldson 的武器是蜕变测试(Metamorphic Testing):既然拿不到绝对答案,那就找输入之间的"等价关系"。比如:把图像先放大再缩小,结果应该接近原图(顺序无关);把着色器的循环展开 2 倍,渲染结果应当像素级一致;把同一份代码用两种优化等级编译,运行输出应当相同。这些"如果 A 成立,那 B 必然也成立"的蜕变关系,本身就是一把隐形的尺子——一旦程序在某个变换下破坏了这种关系,就说明它出 bug 了,哪怕它一个字节都没崩。
Donaldson 团队据此打造了著名的 GraphicsFuzz——专门用蜕变测试猎杀 GPU 驱动和着色器编译器里的深层缺陷。这套工具后来被华为收购,成为工业级 GPU 测试的基石。这是我个人认为视频里最值钱、又最容易被普通观众一耳朵划过去的部分,所以我特意拎出来重点讲:当你的程序"没有标准答案"时,蜕变测试是几乎唯一通用的破局之道。
如果你觉得上面像学术清谈,那看看战果。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 谈的"更聪明"到底有多值钱。
最后一层,是如何落地。现代 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 视频的价值,正在于它把这门"听起来很黑魔法"的技术,还原成了人人能上手的工程实践。
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 这期视频最大的价值,恰恰是它把这门技术从"安全研究员的高墙"里请了出来,放回了每个开发者的工具箱。
模糊测试的真正威力,不在于"随机砸",而在于用覆盖率当罗盘、用 sanitizer 放大破绽、用蜕变关系攻克无解之域——把"找 bug"这件靠运气的事,变成了一台可工程化的、24 小时不眠的猎虫机器。
本文由「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 等场景全覆盖。
