| # Quickstart with CMake | |
| This tutorial describes how to set up your development environment with CMake as | |
| the build system, and how to get a simple fuzz test up and running. We recommend | |
| this tutorial if you're new to FuzzTest or if you need a quick refresher. | |
| ## Definitions | |
| The library can work in several different modes. | |
| * Unit test mode (*default*): FUZZ_TESTs are built without coverage | |
| instrumentation and run with random inputs for short period of time along | |
| with regular unit TESTs. | |
| * Fuzzing mode (controlled by `-DFUZZTEST_FUZZING_MODE=on`): FUZZ_TESTs are | |
| built with coverage instrumentation and run individually and indefinitely or | |
| for specified amount of time. | |
| * Compatibility mode (controlled by | |
| `-DFUZZTEST_COMPATIBILITY_MODE=libfuzzer`): like Fuzzing mode, but an | |
| external engine is used instead FuzzTest's built in engine. Currently | |
| [libFuzzer](https://llvm.org/docs/LibFuzzer.html) is supported. | |
| **Warning:** compatibility mode is experimental and does not guarantee full | |
| FuzzTest features. | |
| ## Overall rules | |
| We provide a default CMake option for unittest mode, the instructions are | |
| straightforward and work like | |
| [googletest](https://google.github.io/googletest/quickstart-cmake.html). | |
| To run in a fuzztest mode, you need to make sure all targets are compiled in a | |
| special way. | |
| * `-g -DFUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION -UNDEBUG` | |
| * `-fsanitize-coverage=inline-8bit-counters -fsanitize-coverage=trace-cmp` | |
| * `-fsanitize=address -DADDRESS_SANITIZER` (optionally enabling sanitizer) | |
| The FuzzTest framework doesn't need to be built with these flags, only the target project. | |
| For all projects to have correct flags set, use a CMake macro | |
| `fuzztest_setup_fuzzing_flags()`. | |
| For a concrete example, see the root CMakeLists.txt. First, we build framework | |
| without additional flags and then build the rest of translation units with | |
| coverage flags. Otherwise we might get into recursive issues, i.e. fuzztest | |
| framework will be fuzzing itself. | |
| Easiest way to make sure you build everything correctly is to invoke | |
| `add_subdirectory` first in your project on fuzztest. | |
| ## Prerequisites | |
| To use FuzzTest, you'll need: | |
| * A Linux-based operating system. | |
| * [Clang](https://clang.llvm.org/). GCC is not yet supported. Unittest mode | |
| mode should work but it's not yet tested. | |
| * [CMake](https://https://cmake.org/). | |
| ## Set up a CMake workspace | |
| First, create a directory where your project will reside: | |
| ```sh | |
| $ mkdir first_fuzz_project && cd first_fuzz_project | |
| $ git clone https://github.com/google/fuzztest.git | |
| ``` | |
| Create a `CMakeLists.txt`. | |
| ``` | |
| cmake_minimum_required(VERSION 3.19) | |
| project(first_fuzz_project) | |
| # GoogleTest requires at least C++17 | |
| set(CMAKE_CXX_STANDARD 17) | |
| add_subdirectory(fuzztest) | |
| ``` | |
| FuzzTest CMake already handles its dependencies on its own: | |
| [RE2](https://github.com/google/re2), | |
| [Abseil](https://github.com/abseil/abseil-cpp). We highly recommend using | |
| [GoogleTest](https://github.com/google/googletest) as well. | |
| ## Create and run a fuzz test | |
| With the CMake workspace set up, you can start using FuzzTest. Let's create a | |
| trivial example to make sure everything runs correctly. | |
| Create a file named `first_fuzz_test.cc` in the directory `first_fuzz` with the | |
| following contents: | |
| ```c++ | |
| #include "fuzztest/fuzztest.h" | |
| #include "gtest/gtest.h" | |
| TEST(MyTestSuite, OnePlustTwoIsTwoPlusOne) { | |
| EXPECT_EQ(1 + 2, 2 + 1); | |
| } | |
| void IntegerAdditionCommutes(int a, int b) { | |
| EXPECT_EQ(a + b, b + a); | |
| } | |
| FUZZ_TEST(MyTestSuite, IntegerAdditionCommutes); | |
| ``` | |
| The file contains two tests in the test suite named `MyTestSuite`. The first one | |
| is a unit test named `OnePlustTwoIsTwoPlusOne` asserting that integer addition | |
| commutes for two specific values. | |
| The second test is a fuzz test that captures the commutative property of integer | |
| addition more generally. The test consists of a property function with a | |
| suggestive name `IntegerAdditionCommutes`, and the test registration using the | |
| macro `FUZZ_TEST`. The property function asserts the commutative property for | |
| two generic integer parameters. | |
| To build and run the tests, **add** to the file `CMakeLists.txt` the following | |
| content: | |
| ```cmake | |
| ... | |
| enable_testing() | |
| include(GoogleTest) | |
| add_executable( | |
| first_fuzz_test | |
| first_fuzz_test.cc | |
| ) | |
| # If you have other dependencies than FuzzTest, link them: | |
| # target_link_libraries(first_fuzz_test PRIVATE other_deps) | |
| link_fuzztest(first_fuzz_test) | |
| gtest_discover_tests(first_fuzz_test) | |
| ``` | |
| This defines a C++ test binary and links it with the FuzzTest and GoogleTest | |
| libraries, as well as the version of the default GoogleTest main that supports | |
| FuzzTest. | |
| ### Unit test mode | |
| There are several ways to run the tests: in the unit test mode and in the | |
| fuzzing mode (see above). The unit test mode runs both test for a short time | |
| without sanitizer and coverage instrumentation: | |
| ``` | |
| $ mkdir build && cd build | |
| $ CC=clang CXX=clang++ cmake \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebug .. | |
| $ cmake --build . | |
| $ ./first_fuzz_test | |
| [==========] Running 2 tests from 1 test suite. | |
| [----------] Global test environment set-up. | |
| [----------] 2 tests from MyTestSuite | |
| [ RUN ] MyTestSuite.OnePlustTwoIsTwoPlusOne | |
| [ OK ] MyTestSuite.OnePlustTwoIsTwoPlusOne (0 ms) | |
| [ RUN ] MyTestSuite.IntegerAdditionCommutes | |
| [ OK ] MyTestSuite.IntegerAdditionCommutes (13 ms) | |
| [----------] 2 tests from MyTestSuite (13 ms total) | |
| [----------] Global test environment tear-down | |
| [==========] 2 tests from 1 test suite ran. (13 ms total) | |
| [ PASSED ] 2 tests. | |
| ``` | |
| ### Fuzzing mode | |
| The fuzzing mode runs a single specified fuzz test with sanitizer and coverage | |
| instrumentation. It keeps running the test with different input values until it | |
| finds a crash or it is explicitly terminated by the user. | |
| Before `add_executable(first_fuzz_test ...)`, add the specified flags: | |
| ```cmake | |
| fuzztest_setup_fuzzing_flags() | |
| ``` | |
| Then run: | |
| ``` | |
| $ CC=clang CXX=clang++ cmake \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebug \ | |
| -DFUZZTEST_FUZZING_MODE=on .. | |
| $ cmake --build . | |
| $ ./first_fuzz_test --fuzz=MyTestSuite.IntegerAdditionCommutes | |
| [.] Sanitizer coverage enabled. Counter map size: 21290, Cmp map size: 262144 | |
| Note: Google Test filter = MyTestSuite.IntegerAdditionCommutes | |
| [==========] Running 1 test from 1 test suite. | |
| [----------] Global test environment set-up. | |
| [----------] 1 test from MyTestSuite | |
| [ RUN ] MyTestSuite.IntegerAdditionCommutes | |
| [*] Corpus size: 1 | Edges covered: 131 | Fuzzing time: 504.798us | Total runs: 1.00e+00 | Runs/secs: 1 | |
| [*] Corpus size: 2 | Edges covered: 133 | Fuzzing time: 934.176us | Total runs: 3.00e+00 | Runs/secs: 3 | |
| [*] Corpus size: 3 | Edges covered: 134 | Fuzzing time: 2.384383ms | Total runs: 5.30e+01 | Runs/secs: 53 | |
| [*] Corpus size: 4 | Edges covered: 137 | Fuzzing time: 2.732274ms | Total runs: 5.40e+01 | Runs/secs: 54 | |
| [*] Corpus size: 5 | Edges covered: 137 | Fuzzing time: 7.275553ms | Total runs: 2.48e+02 | Runs/secs: 248 | |
| [*] Corpus size: 6 | Edges covered: 137 | Fuzzing time: 21.97155ms | Total runs: 9.12e+02 | Runs/secs: 912 | |
| [*] Corpus size: 7 | Edges covered: 137 | Fuzzing time: 166.721522ms | Total runs: 8.49e+03 | Runs/secs: 8491 | |
| [*] Corpus size: 8 | Edges covered: 146 | Fuzzing time: 500.398497ms | Total runs: 2.77e+04 | Runs/secs: 27741 | |
| [*] Corpus size: 9 | Edges covered: 146 | Fuzzing time: 500.821386ms | Total runs: 2.77e+04 | Runs/secs: 27742 | |
| [*] Corpus size: 10 | Edges covered: 147 | Fuzzing time: 2.597553524s | Total runs: 1.75e+05 | Runs/secs: 87476 | |
| ^C | |
| ``` | |
| Congratulations! You're now all set for fuzzing with FuzzTest. | |
| ### Compatibility mode | |
| **Warning:** compatibility mode is experimental and does not guarantee full | |
| FuzzTest features. | |
| ``` | |
| $ CC=clang CXX=clang++ cmake \ | |
| -DCMAKE_BUILD_TYPE=RelWithDebug \ | |
| -DFUZZTEST_COMPATIBILITY_MODE=libfuzzer .. | |
| $ cmake --build . | |
| $ ./first_fuzz_test --fuzz=MyTestSuite.IntegerAdditionCommutes | |
| Note: Google Test filter = MyTestSuite.IntegerAdditionCommutes | |
| [==========] Running 1 test from 1 test suite. | |
| [----------] Global test environment set-up. | |
| [----------] 1 test from MyTestSuite | |
| [ RUN ] MyTestSuite.IntegerAdditionCommutes | |
| FUZZTEST_PRNG_SEED=OffQXb8u5_vZtH4-7wgVOLu_HNAhPIbLz7CFF13u3nk | |
| INFO: found LLVMFuzzerCustomMutator (0x55edfe61cac0). Disabling -len_control by default. | |
| INFO: libFuzzer ignores flags that start with '--' | |
| INFO: Running with entropic power schedule (0xFF, 100). | |
| INFO: Seed: 1109364873 | |
| INFO: Loaded 1 modules (18692 inline 8-bit counters): 18692 [0x55edfe975548, 0x55edfe979e4c), | |
| INFO: Loaded 1 PC tables (18692 PCs): 18692 [0x55edfe979e50,0x55edfe9c2e90), | |
| INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes | |
| INFO: A corpus is not provided, starting from an empty corpus | |
| #2 INITED cov: 17 ft: 18 corp: 1/1b exec/s: 0 rss: 38Mb | |
| #3 NEW cov: 104 ft: 108 corp: 2/66b lim: 4096 exec/s: 0 rss: 38Mb L: 65/65 MS: 1 Custom- | |
| #4 NEW cov: 105 ft: 112 corp: 3/121b lim: 4096 exec/s: 0 rss: 38Mb L: 55/65 MS: 1 Custom- | |
| #5 NEW cov: 105 ft: 113 corp: 4/196b lim: 4096 exec/s: 0 rss: 38Mb L: 75/75 MS: 1 Custom- | |
| #16 REDUCE cov: 105 ft: 113 corp: 4/195b lim: 4096 exec/s: 0 rss: 38Mb L: 54/75 MS: 1 Custom- | |
| #41 NEW cov: 105 ft: 114 corp: 5/247b lim: 4096 exec/s: 0 rss: 38Mb L: 52/75 MS: 5 Custom-Custom-Custom-Custom-Custom- | |
| #65 NEW cov: 106 ft: 115 corp: 6/312b lim: 4096 exec/s: 0 rss: 38Mb L: 65/75 MS: 4 Custom-Custom-Custom-Custom- | |
| #69 NEW cov: 108 ft: 119 corp: 7/365b lim: 4096 exec/s: 0 rss: 38Mb L: 53/75 MS: 4 Custom-Custom-Custom-Custom- | |
| ``` | |
| ## Next steps | |
| * This tutorial covered the basic setup of the build environment with CMake. | |
| To learn more about the FuzzTest framework and how to use it, check out the | |
| [Codelab](tutorial.md). | |
| * Explore the rest of the [documentation](./). |