← Concepts

阅读中文版本

Coverage-Guided Fuzzing

Coverage-guided fuzzing evolves random inputs toward new code paths, using instrumentation feedback to mutate seeds that reach unexplored branches — beyond human test imagination.

testing

Definition

Coverage-guided fuzzing runs the target with mutated inputs while instrumentation reports which code executed. Inputs reaching new coverage become seeds for further mutation, evolving a corpus that explores deep paths — parsers, decoders, protocol handlers — and crashes on invalid assumptions. American Fuzzy Lop pioneered the approach; libFuzzer and OSS-Fuzz industrialized it.

Context and scope

Applied continuously to parsers, codecs, crypto implementations, and protocol stacks. Structured fuzzing uses grammars or dictionaries; in-process fuzzing targets library APIs directly.

Common misconceptions

  • Fuzzing replaces test design — it complements it; fuzzing finds the cases nobody thought to write, tests pin the cases that matter
  • Random inputs only scratch the surface — feedback-driven mutation drives coverage deep; the classic one-liner inputs of pure random fuzzing are long obsolete
  • Crashes are the only output — coverage growth, stability, and timeout reports are equally valuable signals about robustness

Anti-patterns

  • Fuzzing black-box binaries without symbols or coverage and burning CPU on blind mutation
  • Ignoring non-crashing hangs and OOM reports as noise when they are availability bugs
  • Seeding with only empty and trivial inputs and starving the corpus of valid structure

Related concepts

Related examples

Authoritative source

https://www.llvm.org/docs/LibFuzzer.html

What it is

Human-written test cases explore the paths humans imagine. The fuzzer enumerates the rest: it breeds inputs from coverage feedback, retaining mutants that discovered new branches and discarding the redundant.

How it works

Instrumentation (compile-time or binary translation) maps each input to a coverage signature. The engine mutates seeds — byte flips, splices, dictionary tokens — keeps inputs with novel signatures, and logs failures: crashes, hangs, OOM. Structured targets use grammar-aware mutators or protocol state models to generate valid-enough inputs that reach deep code.

When to deploy

Anything parsing untrusted bytes: file formats, network protocols, JWT and cookie parsing, image decoders, template engines. Run continuously on a corpus committed to the repository so each run inherits past discoveries.

Pitfalls

Coverage novelty saturates: growth flattens and the fuzzer idles — add dictionaries, grammar seeds, or structure-aware mutators to reopen paths. Crashes require minimization before they are actionable; a reproducer without a reduced case becomes triage debt. Deterministic builds matter — unreproducible binaries make crashes unfixable.