Fuzzing the PDF engine
fuzz_load.cpp is a libFuzzer harness that drives the full
load → metadata → outline → render → text → annotations → hit-test → select
path with arbitrary bytes. Combined with AddressSanitizer it surfaces crashes,
OOMs, and undefined behaviour in the parsing and rendering code.
Resource ceilings from pdfengine/hardened_limits.h keep the fuzzer focused on
logic bugs instead of trivial out-of-memory inputs (and those same ceilings now
guard the production render path against integer-overflow / OOM).
Linux (primary)
Clang + libFuzzer + ASan is best supported on Linux. PDFium must be built with the same Clang toolchain (so ASan is consistent across the static lib).
# Full ASan + coverage fuzzer
cmake --preset fuzz-linux
cmake --build --preset fuzz-linux
# If your PDFium static lib is NOT ASan-instrumented, use coverage-only:
cmake --preset fuzz-linux-nosan
cmake --build --preset fuzz-linux-nosan
# Run it against the downloaded corpus as a seed set
python scripts/fetch_corpus.py # populates corpus/fuzz/ (gitignored)
mkdir -p engine/fuzz/artifacts
./out/build/fuzz-linux/bin/pdfengine_fuzz \
-artifact_prefix=engine/fuzz/artifacts/ \
corpus/fuzz/ corpus/
corpus/fuzz/ and corpus/ are passed as seed corpora; new coverage-expanding
inputs are written back into the first directory. Crashes land in
engine/fuzz/artifacts/ (gitignored).
Windows (clang-cl)
Native Windows fuzzing needs a Clang toolchain and a PDFium static lib built
with the matching runtime. Configure with clang-cl and the existing
x64-windows-static triplet, then enable fuzzing:
cmake -S . -B C:/Users/<you>/pdfeng-build/fuzz-win -G Ninja `
-DCMAKE_C_COMPILER=clang-cl -DCMAKE_CXX_COMPILER=clang-cl `
-DVCPKG_TARGET_TRIPLET=x64-windows-static `
-DPDFENGINE_FUZZING=ON -DPDFENGINE_WITH_PDFIUM=ON `
-DPDFENGINE_FUZZ_SANITIZERS=fuzzer `
--toolchain "$env:VCPKG_ROOT/scripts/buildsystems/vcpkg.cmake"
cmake --build C:/Users/<you>/pdfeng-build/fuzz-win
Use PDFENGINE_FUZZ_SANITIZERS=fuzzer (coverage-only) on Windows unless the
whole dependency chain — including PDFium — is ASan-built, since mixing an
ASan binary with a non-ASan MSVC static lib does not link cleanly.
Reproducing a crash
./pdfengine_fuzz engine/fuzz/artifacts/crash-<hash>
The ASan report points at the offending allocation/access; the input file is the
minimal reproducer (run with -minimize_crash=1 to shrink further).