Bug 发现活动
选择一个能够暴露新违反保证的实验,然后根据实验实际观察到的结果分配计算资源。保持发现、复现和分类的成本可见。速度是列出的性能因素之一,与“代码覆盖率应随时间增长”和解决阻塞问题并列,一个有用的目标“必须在它测试的代码中有良好的覆盖率”;仅凭执行次数并不能建立有用的 reach(OSS-Fuzz 集成,覆盖率,ClusterFuzz 性能,性能因素)。
评估当前能力
读取实际的目标版本、启用的构建、harness 生产者和断言体。记录每个现有通道可以执行和观察的输入、初始状态、操作、效果、调度、失败和配置。检查排除项和被拒绝的情况。仅在相关文档记录的构建/运行时适用时,才使用覆盖率或可达性工具;Fuzz Introspector 记录的报告“针对用 C/C++、Python 和 Java 编写的项目”,每种都有自己的构建工具集,因此它不是一个通用的后端(Fuzz Introspector,概述和构建工具的差异)。对于 JavaScript 或 TypeScript 项目,请阅读 JS 通道清单。
当检查的实现提供了该能力时,将其视为现有能力。对于已经使用有效程序生成、跨引擎结果比较和事务历史记录的目标,添加同名的新机制并非所提议的进步。而是选择未覆盖的交互或观察:SQLite 的 dbsqlfuzz “同时改变 SQL 输入和数据库文件”,并发现了“之前模糊测试遗漏”的故障,这是一个同时搜索多个维度的具体先例。它是一个“专有的模糊测试工具”:借鉴其机制,而非假定其公开工具可用(SQLite 测试,§2 和 §4.1.3)。
使一个候选可执行
在项目现有的实验笔记中描述该候选方案;不要引入服务或强制使用的模式。将这些决策及其证据路径放在一起。OSS-Fuzz 要求目标在短时间的本地运行中“至少取得一些进展”,并且复现需要与报告匹配的构建(OSS-Fuzz 集成,Fuzz 目标,复现,构建镜像和 fuzzer):
- 生产者和缺口: 实际的入口点加上基线遗漏的失败空间。
- 保证和预言: 治理契约、可执行的观察以及合法/不支持/不确定的结果。
- 搜索: 生成的值/状态/操作以及任何受控的调度、故障或配置选择。
- 试点: 授权的已用时间/工作程序/资源信封、回放材料以及将证明下一次分配合理性的证据。
在增加工作负载之前设计观察。Elle 的可追踪对象揭示了普通覆盖写入所隐藏的依赖关系,因为对寄存器的盲目写入“会破坏历史”。其推理也有明确的限制:检查器是健全的并且“接近保证完备性”,并且“我们的方法忽略谓词,仅处理单个对象”。生成更多无信息历史的生成器无法修复这些限制(Elle,§§3、4.3 和 9)。对于通用契约,请使用 correctness-oracles,对于其特定模型,请使用下面的专用工具。
| 缺失的维度或观察 | 相关专业工具 |
|---|---|
| 依赖的 API 对象和合法的操作序列 | stateful-property-testing |
| 无需操作模型即可到达的浏览器或 React UI 状态,带有每状态预言和路径回放 | ui-state-exploration |
| 具有所需状态/效果的运行时有效程序 | semantic-program-generation |
| 独立执行比较或合理的运行间关系 | semantic-differential-testing,metamorphic-testing |
| 工具/搜索机制或保留的搜索材料 | coverage-guided-fuzzing,corpus-evolution |
| 内存访问诊断或受控的调度选择 | native-memory-instrumentation,race-detection-campaigns,schedule-exploration |
| 并发对象或事务保证 | linearizability-checking,transactional-history-testing |
| 部署故障、受控环境或恢复边界 | distributed-fault-testing,deterministic-simulation,crash-consistency-testing |
| 硬路径约束或有界不变量 | symbolic-concolic-execution,bounded-model-checking |
| 资源增长、进度、构建交互或数值精度 | resource-complexity-testing,liveness-testing,configuration-differential-testing,numerical-oracles |
该表格路由此工具包的职责;它并不确定命名工具支持该目标。仅阅读选定的专业工具及其适用的参考文献。使用 harness-sensitivity 来获取证据,证明新的预言能够到达并拒绝具有代表性的违规,最好是通过现有的回归测试或控制;SQLite 的突变测试“验证测试套件是否捕获了突变”(SQLite 测试,§7.6)。使其与实验成比例,而不是一个重复的审批轮次。
根据试点证据分配
在授权的信封内运行。检查目标代码和预期属性是否得到执行;区分不可达路径和突变尚未解决的路径。Fuzz Introspector 比较每个 fuzzer 的“静态可达潜力”与动态覆盖率,以进行此区分。当缺失的生产者、语义先决条件或观察是限制因素时,更改实验(Fuzz Introspector,概述)。有关诊断,请阅读试点诊断。
当一个信息丰富的通道的证据证明更多搜索是合理的时,扩展它。在搜索机制不同的互补通道之间进行比较;AFL++ 说“对于每个辅助 fuzzer,应该有一个变体”(AFL++ 深入,§3.c 使用多核)。使用实际的时间、工作程序和资源限制,而不是通用的持续时间或核心数。将运行时标志保留在专业工具中;每次输入的超时、活动持续时间和内存限制是不同的控制(libFuzzer 23.1.0 选项)。
保留属性评估和语义/代码覆盖的原始计数器、原始候选和再现的发现结果、重复项和未知项,以及设置/执行/缩减/分类成本。不要将它们合并为虚构的生产率分数。当比较性声明很重要时,使用匹配条件和重复试验并考虑变异性;FuzzBench 报告“试验次数、均值、中位数、标准”偏差以及“达到的覆盖率的分布”,而不是单个幸运的运行(FuzzBench 报告,每个基准的摘要)。
在总结之前,保留原始输入、起始状态、源代码/构建/配置、工具化、原始输出和回放选择。一个 OSS-Fuzz 测试用例“包含提供给”目标的字节,并且有些 bug“仅在 32 位模式或仅在 64 位模式下”在报告的消毒器下可重现;单独的种子不是那个完整的工件(OSS-Fuzz 复现,Fuzz 目标 bug 和 构建镜像和 fuzzer)。将候选路由到 failure-reduction 和 evidence-based-triage;使不可靠或未解决的发现结果保持可见,而不是默默计数或丢弃它们。ClusterFuzz 根据复现的可靠性进行过滤,并保留“问题发生频率及条件的统计信息”(ClusterFuzz 分类,过滤测试用例和崩溃统计)。
完成分配决策
记录继续、改变维度、复现/缩减/分类或停止,附带观察到的原因和剩余空间。平台期促使进行诊断;它既不能证明正确性,也不能证明其他工具会有所帮助。将零发现作为有界的结果保留。未处理的候选队列可以证明将下一笔预算花在证据上而不是生成上是合理的。对于覆盖率引导的 libFuzzer 或 AFL 目标,ClusterFuzz 建议,当一个目标发现许多新的崩溃时,“修复它们可能比分析性能更重要”(ClusterFuzz 性能,何时分析 fuzz 目标性能)。
返回测试的保证、实际预算、到达的行为、证据路径、分类的发现和下一个决策。在已建立的情况下描述用户可见的影响;将可能的原因与已证明的违规分开。有关已工作的分配和记录,请阅读活动示例;有关误导性的捷径,请阅读常见错误。
调用保留用户现有的范围和执行规则。它本身不授权目标更改、安装、云支出、生产故障注入或外部发布。