Coverage-guided fuzzing across every mainstream engine - libFuzzer (C/C++ in-process), AFL++ (out-of-process, QEMU mode for closed-source binaries), cargo-fuzz (Rust), Go native fuzzing (go test -fuzz), Atheris (Python), and Jazzer (JVM, @FuzzTest). Body covers choosing the right fuzzer for the language and build type (the routing tree) plus the engine-generic workflow: writing a small deterministic fuzz target, seed-corpus + dictionary construction, sanitizer selection (ASan + UBSan default, compatibility matrix), corpus minimisation, crash-artifact handling, and CI smoke-fuzz wiring with a cached corpus. Per-engine depth (flags, harness syntax, CI jobs) lives in references, as do the corpus-management and sanitizer-integration catalogs. Use when a project needs fuzz coverage and no fuzzer is chosen yet, or when authoring / running / maintaining a fuzz campaign with any of these engines. For triaging the resulting crashes see crash-triage-reference.
70
88%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
View guide
Passed
No findings from the security scan
Shared reference for coverage-guided-fuzzing; the per-engine references
and the umbrella workflow live alongside this file.
Pure-reference catalog of the five clang sanitisers (ASan, UBSan, MSan, TSan, LSan) used with coverage-guided fuzz targets - what each detects, build flags, runtime options, compatibility matrix, performance overhead. Consumed by the per-engine references and fuzz-target authoring. For corpus discipline see corpus-management.md.
-fsanitize=fuzzer,<sanitisers> plus -fno-sanitize-recover=all and -fno-omit-frame-pointer -g.ASAN_OPTIONS, UBSAN_OPTIONS) so the fuzzer aborts on first error.| Sanitiser | Detects (summary) | Build flag | Slowdown |
|---|---|---|---|
| ASan | heap / stack / global OOB, use-after-free, double-free | -fsanitize=address -fno-omit-frame-pointer -g | ~2x |
| UBSan | signed overflow, div-by-zero, null deref, misaligned access | -fsanitize=undefined -fno-sanitize-recover=all | ~10% |
| MSan | uninitialised memory reads | -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins | 3x |
| TSan | data races, deadlocks, thread-safety violations | -fsanitize=thread -O1 -g | 5 - 15x |
| LSan | memory leaks at program exit | -fsanitize=leak (or embedded in ASan) | small |
Full per-sanitiser detail - complete detect lists, the ASAN_OPTIONS /
UBSAN_OPTIONS runtime-option tables, the MSan whole-program requirement, and
LSan's embedded vs standalone modes: see "Per-sanitiser catalog" below.
Can multiple sanitisers run in the same binary?
| Sanitiser | ASan | UBSan | MSan | TSan |
|---|---|---|---|---|
| ASan | - | ✓ | ✗ | ✗ |
| UBSan | ✓ | - | ✓ | ✓ |
| MSan | ✗ | ✓ | - | ✗ |
| TSan | ✗ | ✓ | ✗ | - |
The standard fuzzing pair is ASan + UBSan (catches most memory + UB issues, manageable slowdown):
clang -g -O1 -fsanitize=fuzzer,address,undefined \
-fno-sanitize-recover=all \
-fno-omit-frame-pointer fuzz_target.cc -o fuzz_targetFor MSan-required projects (e.g., crypto libraries), build a separate MSan-only binary and run it as a second fuzzing campaign.
The -fsanitize=fuzzer,address,undefined flag composes the
libFuzzer engine with ASan + UBSan in one binary. Each sanitiser
contributes its instrumentation.
Per llvm.org/docs/LibFuzzer.html:
# Build
clang -g -O1 \
-fsanitize=fuzzer,address,undefined \
-fno-sanitize-recover=all \
fuzz_target.cc -o fuzz_target
# Run
ASAN_OPTIONS=abort_on_error=1:halt_on_error=1 \
UBSAN_OPTIONS=print_stacktrace=1:halt_on_error=1 \
./fuzz_target -max_total_time=3600 corpus/ASan output structure:
==1234==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7f...
READ of size 4 at 0x7f... thread T0
#0 0x4015a3 in process_input src/parser.c:42:5
#1 0x4012f0 in LLVMFuzzerTestOneInput fuzz_target.cc:10:3
...
0x7f... is located 0 bytes to the right of 16-byte region 0x7f..., 0x7f...)
allocated by thread T0 here:
#0 0x40e7c0 in __interceptor_malloc
#1 0x4015a3 in process_input src/parser.c:39:9Key fields:
heap-buffer-overflow, stack-use-after-return,
use-after-free, double-free, memory-leakParse this for the from-CI-failure workflow in bug-report-template
(qa-bug-repro plugin) to extract the failure assertion.
| Language | ASan | UBSan | MSan | TSan | LSan |
|---|---|---|---|---|---|
| C / C++ (clang / GCC) | ✓ | ✓ | ✓ (clang) | ✓ | ✓ |
| Rust (nightly) | ✓ | ✓ | ✓ | ✓ | ✓ |
| Go | partial (race detector for TSan-equivalent) | - | - | ✓ | - |
| Swift | ✓ | ✓ | - | ✓ | ✓ |
| Objective-C | ✓ | ✓ | - | ✓ | ✓ |
Java / Kotlin (Jazzer) uses JVM-level sanitisers (sanitisers for unsafe-API misuse, deserialisation gadgets, ReDoS) rather than clang's; see jazzer.md.
Python (Atheris) uses per-module instrumentation + the host process's libFuzzer; you can attach ASan to the Python interpreter itself.
A team fuzzes a C++ PNG parser. They choose ASan + UBSan (the standard pair) and build with:
clang -g -O1 -fsanitize=fuzzer,address,undefined \
-fno-sanitize-recover=all -fno-omit-frame-pointer \
png_fuzzer.cc -o png_fuzzerRunning under ASAN_OPTIONS=abort_on_error=1:halt_on_error=1, the fuzzer trips
within minutes. The report opens with heap-buffer-overflow ... READ of size 4,
top frame process_input src/parser.c:42, allocated at src/parser.c:39 (a
16-byte region). The bug class plus the allocation site pin it to an off-by-one in
the chunk-length handling. The parser has no MSan dependency requirement, so they
skip the separate MSan binary and hand the report to the from-CI-failure workflow in bug-report-template.
| Anti-pattern | Why it fails | Fix |
|---|---|---|
| Fuzzing without sanitisers | Catches only crashes; misses 80%+ of memory bugs | Always build with ASan + UBSan minimum |
-fsanitize=address,memory together | MSan + ASan incompatible | Pick one; run separate binaries |
| MSan with non-MSan dependencies | False positives flood the report | Build all dependencies with MSan or skip MSan |
UBSan without -fno-sanitize-recover=all | UBSan logs but doesn't abort; fuzzer never sees the bug | Always add -fno-sanitize-recover=all |
ASan without -fno-omit-frame-pointer | Stack traces are useless | Always add -fno-omit-frame-pointer -g |
detect_leaks=0 in fuzz CI | Leak bugs go unnoticed | Default ASan settings (Linux LSan-enabled) |
| TSan + a non-thread-safe target | Slow + noisy; data races are everywhere | Pick targets where thread-safety claims are made |
-DCMAKE_C_FLAGS=-fsanitize=...).What it detects (per clang.llvm.org/docs/AddressSanitizer.html):
Build flag: -fsanitize=address -fno-omit-frame-pointer -g
Performance: "Typical slowdown introduced by AddressSanitizer is 2x" per the docs.
Runtime options (ASAN_OPTIONS=key=value:...):
| Option | Effect |
|---|---|
detect_leaks=1 | Enable leak detection (default on Linux) |
detect_stack_use_after_return=0 | Disable use-after-return checks (faster) |
detect_container_overflow=0 | Disable container-overflow detection |
symbolize=0 | Disable online symbolization (use post-mortem) |
check_initialization_order=1 | Init-order checking |
halt_on_error=1 | Stop on first error |
abort_on_error=1 | SIGABRT on error (for fuzzers) |
What it detects: signed integer overflow, division by zero, null pointer deref, misaligned access, float-int conversion overflow, invalid enum / bool, vptr corruption, function-pointer type mismatch, etc.
Build flag: -fsanitize=undefined -fno-sanitize-recover=all
The -fno-sanitize-recover=all is important for fuzzing - without
it, UBSan logs but doesn't abort, so the fuzzer doesn't see the
bug.
Performance: ~10% slowdown - much lighter than ASan.
Runtime options (UBSAN_OPTIONS):
print_stacktrace=1 - include stack trace in reportshalt_on_error=1 - abort on first errorWhat it detects: Uninitialised memory reads.
Build flag: -fsanitize=memory -fno-omit-frame-pointer -fsanitize-memory-track-origins
Performance: 3x slowdown.
Critical: MSan requires the entire program (and all
dependencies) to be built with -fsanitize=memory. Linking
against non-MSan-instrumented libraries produces false positives.
Compatibility: MSan is incompatible with ASan; cannot combine.
What it detects: Data races, deadlocks, thread-safety violations.
Build flag: -fsanitize=thread -O1 -g
Performance: 5 - 15x slowdown + 5 - 10x memory.
Compatibility: TSan is incompatible with ASan and MSan.
What it detects: Memory leaks at program exit.
Modes:
-fsanitize=address enables LSan by default
on Linux. Toggle via detect_leaks=1.-fsanitize=leak - leak detection only, no other
checks. Smaller overhead.