pw_fuzzer#

Better C++ code through easier fuzzing

Unstable C++17 C++20

Use state of the art tools to automatically find bugs in your C++ code with 5 lines of code or less!

FUZZ_TEST(MyTestSuite, TestMyInterestingFunction)
  .WithDomains(Arbitrary<size_t>(), AsciiString());

Background#

You’ve written some code. You’ve written unit tests for that code. The unit tests pass. But could there be bugs in inputs or code paths the unit tests do not cover? Fuzzing can help!

However, fuzzing requires some complex interactions between compiler-added instrumentation, compiler runtimes, code under test, and the fuzzer code itself. And to be reliably useful, fuzzers need to be part of a continuous fuzzing infrastructure, adding even more complexity.

See pw_fuzzer: Concepts to learn more about the different components of a fuzzer and how they work together to discover hard-to-find bugs.

Our solution#

pw_fuzzer makes it easier to write, build, run, and deploy fuzzers. It provides convenient integration with two fuzzing engines:

  • libFuzzer, allowing integration of legacy fuzzers.

  • FuzzTest, allowing easy creation of fuzzers from unit tests in around 5 lines of code.

Additionally, it produces artifacts for continuous fuzzing infrastructures such as ClusterFuzz and OSS-Fuzz, and provides the artifacts those systems need.

Who this is for#

pw_fuzzer is useful for authors of wide range of C++ code who have written unit tests and are interested in finding actionable bugs in their code.

In particular, coverage-guided is effective for testing and finding bugs in code that:

  • Receives inputs from untrusted sources and must be secure.

  • Has complex algorithms with some equivalence, e.g. compress and decompress, and must be correct.

  • Handles high volumes of inputs and/or unreliable dependencies and must be stable.

Fuzzing works best when code handles inputs deterministically, that is, given the same input it behaves the same way. Fuzzing will be less effective with code that modifies global state or has some randomness, e.g. depends on how multiple threads are scheduled. Simply put, good fuzzers typically resemble unit tests in terms of scope and isolation.

Is it right for you?#

Currently, pw_fuzzer only provides support for fuzzers that:

  • Run on host. Sanitizer runtimes such as AddressSanitizer add significant memory overhead and are not suitable for running on device. Additionally, the currently supported engines assume the presence of certain POSIX features.

  • Are built with Clang. The instrumentation used in fuzzing is added by clang.

Getting started#

The first step in adding a fuzzer is to determine what fuzzing engine should you use. Pigweed currently supports two fuzzing engines:

  • FuzzTest is the recommended engine. It makes it easy to create fuzzers from your existing unit tests, but it does requires additional third party dependencies and at least C++17. See pw_fuzzer: Adding Fuzzers Using FuzzTest for details on how to set up a project to use FuzzTest and on how to create and run fuzzers with it.

  • libFuzzer is a mature, proven engine. It is a part of LLVM and requires code authors to implement a specific function, LLVMFuzzerTestOneInput. See pw_fuzzer: Adding Fuzzers Using LibFuzzer for details on how to write fuzzers with it.

Roadmap#

pw_fuzzer is under active development. There are a number of improvements we would like to add, including:

  • b/282560789 - Document workflows for analyzing coverage and improving fuzzers.

  • b/280457542 - Add CMake support for FuzzTest.

  • b/281138993 - Add a pw_cli plugin for fuzzing.

  • b/281139237 - Develop OSS-Fuzz and ClusterFuzz workflow templates for downtream projects.