← 中文资源

简体中文版本

覆盖引导模糊测试

覆盖引导模糊测试借助插桩反馈演化随机输入,让命中未探索分支的种子继续变异——把用例生成扩展到人类想象力之外。

阅读英文原文

概念定义

人写的用例探索人想象得到的路径,模糊器枚举其余:从覆盖反馈中育种输入,保留发现新分支的变异体、丢弃冗余者。

工作机制

插桩(编译期或二进制翻译)把每个输入映射到覆盖签名;引擎变异种子——字节翻转、拼接、字典令牌——保留签名新颖的输入,并记录崩溃、挂起、OOM。结构化目标用文法感知变异器或协议状态模型生成“足够有效”以深入代码的输入。

使用场景

一切解析不可信字节的东西:文件格式、网络协议、JWT 与 Cookie 解析、图像解码器、模板引擎。语料库提交进仓库持续运行,每次都继承过去的发现。

常见误区

模糊是补充不是替代:它找没人想到的用例,测试钉住要紧的用例。“纯随机只能挠表面”早已过时——反馈驱动的变异能把覆盖推得很深。对无符号无覆盖的黑盒二进制盲变异是烧 CPU;挂起与 OOM 不是噪声而是可用性 bug;只喂空与平凡输入会饿死语料库的结构多样性。崩溃要先最小化才可执行,不可复现的二进制让崩溃无解。

代码示例

export interface PropertyCase { readonly numbers: number[]; }

export function check(numbers: number[]): boolean {
  return numbers.every((n, i) => i === 0 || (numbers[i - 1] as number) <= n);
}

export function shrink(failing: number[], holds: (input: number[]) => boolean): number[] {
  let current = failing;
  let changed = true;
  while (changed) {
    changed = false;
    for (let i = 0; i < current.length; i++) {
      const candidate = current.filter((_, index) => index !== i);
      if (!holds(candidate)) {
        current = candidate;
        changed = true;
        break;
      }
    }
  }
  return current;
}

export function findCounterexample(seed: number[], holds: (input: number[]) => boolean): number[] | null {
  if (!holds(seed)) return shrink(seed, holds);
  return null;
}