October 12, 2026
| Unit testing | Fuzzing |
|---|---|
| Human-written inputs and/or parametrization | Machine-generated inputs |
| Emphasize “reasonable” inputs (even error cases) | Accidentally produces “pathological” inputs… by design |
| Deterministic (ideally, otherwise a bug) | Stochastic by design |
| Stateless | Stateful to avoid searching from scratch every time |
| Easy to set up (wide-spread, mature tooling, well-known best practices) | Difficult to set up |
| Finds bugs immediately ⇒ can synchronously block PRs | Can take a lot of time (potentially infinite) ⇒ bugs often found long after merging |
| 100% coverage a (theoretical) goal | Opportunistic: only fuzz the most sensitive code paths |
| Needs maintenance to stay relevant | Needs maintenance to stay relevant |
⇒ The two techniques are complementary!
unique_ptr, shared_ptr): ✔️ alwaysthis: 💣 potentially unsafe (except in constructor & destructor)this can suddenly become invalidshared_ptr, enable_shared_from_this, weak_ptr) require more typing, more boilerplate, and are generally less easy to use.Summary of required items:
You can try to do all this by yourself, or use off-the-shelf facilities.
Enter OSS-Fuzz.
Project approval is opaque.
To be accepted to OSS-Fuzz, an open-source project must have a significant user base and/or be critical to the global IT infrastructure.
(you could set up ClusterFuzz or ClusterFuzzLite on your own infrastructure)
Project governance is unclear.
Maintenance status is unclear (is Google still engaged?).
Some tooling a bit clunky.
Not much interaction between OSS-Fuzz maintainers and project authors.
(if you are a OSS-Fuzz maintainer and this doesn’t feel right, please tell me)
| Language | Number of projects |
|---|---|
| C/C++ | 592 |
| Go | 150 |
| JavaScript | 27 |
| JVM-based | 231 |
| Python | 278 |
| Ruby | 2 |
| Rust | 89 |
| Swift | 3 |
Executive summary: 3 files required in the OSS-Fuzz repository
project.yaml: (short) metadata about the projectDockerfile: environment in which the project is built for fuzzingbuild.sh: build script for the projectThe Docker environment uses custom OSS-Fuzz base images with wrapper scripts for building the project.
Please read the fine docs: “Setting up a new project”
A fuzz target is an executable made by linking the fuzzing engine (e.g. libFuzzer) with the code you want to fuzz.
The fuzzing engine defines its own main function that exposes a CLI for fuzzing. It calls into a predefined entry point each time it wants to execute the function under test.
When an issue is detected while fuzzing, project maintainers are privately notified by e-mail.
Issue details can be browsed on a dedicated issue tracker with restricted access; reproducers can be downloaded for local investigation.
If you push a fix to your codebase, later OSS-Fuzz builds of your project (presumably the day after) will pick it up the and detect that the issue cannot be reproduced anymore; the issue will then be closed.
It is critical to help the fuzzing engine generate potentially interesting inputs:
A fuzz target is an executable that combines the fuzzing engine and the function under test.
Arrow C++ defines fuzz targets for these components:
Components selected because of:
ARROW_FUZZING to enable fuzz targets and utilitiesDockerfile downloads fresh Boostbuild.sh
Fuzz-related builds on the mainline Arrow CI:
A Docker-based build replicating the OSS-Fuzz build step (not the fuzzing).
A ASan/UBSan-enabled build that checks for regressions against all OSS-Fuzz issue reproducers (+ runs the regular C++ test suite).
Arrow C++ validation APIs are designed to accept untrusted inputs, they are exercised by the fuzzers.
LibFuzzer crashes when a fixed memory ceiling is reached
OSS-Fuzz does not support fuzz target parametrization
Parquet has many optional features and we strive to exercise most of them.
The Parquet fuzzer tries to read its payload as an entire Parquet file.
The seed corpus consists of:
parquet-testing repositoryGoal: exercise the Parquet encoders and decoders specifically.
A parametric fuzzer with the following parameters:
Runs the following steps:
Goal: exercise various flavors of the Arrow CSV reader (serial, multi-threaded, streaming)
Fuzzer tries to read its payload as a CSV file, using different CSV reader APIs; validates the results.
Seed corpus consists of:
arrow-testing repository| Fuzz target | First run | First bug | Last bug | # bugs found | Seed corpus | OSS-Fuzz corpus |
|---|---|---|---|---|---|---|
| arrow-ipc-stream-fuzz | 2020-01-15 | 2020-01-16 | 2026-03-04 | 68 | 133 files, 2 MB | 35854 files, 93 MB |
| arrow-ipc-file-fuzz | 2020-01-15 | 2020-01-16 | 2026-04-24 | 55 | 133 files, 2.1 MB | 43357 files, 98 MB |
| arrow-csv-fuzz | 2025-10-13 | 2025-10-14 | 2025-12-10 | 8 | 53 files, 3.9 MB | 7305 files, 169 MB |
| parquet-arrow-fuzz | 2020-02-12 | 2020-02-13 | 2026-01-13 | 109 | 571 files, 8.9 MB | 31257 files, 302 MB |
| parquet-encoding-fuzz | 2026-03-03 | 2026-03-05 | 2026-06-07 | 7 | 144 files, 2.6 MB | 9716 files, 149 MB |
This presentation: https://pitrou.net/coc-glasgow-2026/Fuzzing.html
“Fuzzing Arrow C++” in the Arrow documentation: https://arrow.apache.org/docs/dev/developers/cpp/fuzzing.html
libFuzzer documentation: https://llvm.org/docs/LibFuzzer.html
OSS-Fuzz documentation: https://google.github.io/oss-fuzz/
Recent work on fuzzing Arrow was funded by the Sovereign Tech Fund – thanks to STF!