Write a C/C++ Fuzz Test
Structure of a Fuzz Test
#include "<target>.h"
#include <cifuzz/cifuzz.h>
FUZZ_TEST_SETUP() {
// Optional one-time setup
}
FUZZ_TEST(const uint8_t *data, size_t size) {
// Call target function with data
}
The Fuzz Test must include the header for the target function and cifuzz
itself to be able to run.
One-time setup required by the FUZZ_TEST
function can be configured in FUZZ_TEST_SETUP()
.
FuzzedDataProvider
While not required, it is recommended to use the FuzzedDataProvider
in your Fuzz Test to split the fuzzing input in
the data
variable into different data types, which you can as parameters for the function you want to fuzz.
FUZZ_TEST(const uint8_t *data, size_t size) {
FuzzedDataProvider fuzzed_data(data, size);
int a = fuzzed_data.ConsumeIntegral<int>();
targetFunction(a);
}
The C++ implementation of the FuzzedDataProvider
is part of the LLVM Project. You can find the
documentation in
Google's Fuzzing repository
and
the LLVM repository.
Create a Fuzz Test template
You can run the following cifuzz
command to create a Fuzz Test template in the specified location:
cifuzz create cpp -o <path to fuzz test>
Create your Fuzz Tests close to the code being tested, just as you would for a unit test.
Integrate a Fuzz Test into your project
Depending on your build system, the following steps are needed to successfully integrate the Fuzz Test into your project.
CMake
After creating your Fuzz Test, you need to add it with the add_fuzz_test
command to your CMakeLists.txt
file and
link the target library:
add_fuzz_test(<fuzz test name> <path/to/fuzz_test.cpp>)
target_link_libraries(<fuzz test name> PRIVATE <target>)
Bazel
After creating your Fuzz Test, you need to define a Bazel target by adding the following to the BUILD.bazel
file:
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzz_test")
cc_fuzz_test(
name = "<fuzz test name>",
srcs = ["<fuzz test.cpp>"],
corpus = glob(
["<fuzz test name>_inputs/**"],
allow_empty = True,
),
deps = [
"//<target>",
"@cifuzz"
],
)
Make
After creating your Fuzz Test, you need to create a target in the Makefile
for the Fuzz Test:
lib<target>.so: <path/to/target.cpp> <path/to/target.h>
${CXX} ${CXXFLAGS} -shared -fpic -o lib<target>.so $<
<fuzz test name>: <target>.so
${CXX} ${CXXFLAGS} ${FUZZ_TEST_CFLAGS} ${FUZZ_TEST_LDFLAGS} -o $@ $@.cpp -Wl,-rpath '-Wl,$$ORIGIN' -L. -l<target>
When running the Fuzz Test, CI Fuzz sets the following environment variables:
- CC - Sets the C compiler to clang
- CXX - Sets the C++ compiler to clang++
- CFLAGS - Sets the necessary C compiler and linker flags that should be used for the Fuzz Test and the software under test
- CXXFLAGS - Sets the necessary C++ compiler and linker flags that should be used for the Fuzz Test and the software under test
- FUZZ_TEST_CFLAGS - Sets the necessary compiler flags that should be used for the Fuzz Test
- FUZZ_TEST_LD_FLAGS - Sets the necessary linker flags that should be used for the Fuzz Test
FUZZ_TEST_CFLAGS
and FUZZ_TEST_LDFLAGS
are environment variables which must both be passed to the compiler and
linker command for the Fuzz Test. The CC
and CFLAGS
/CXX
and CXXFLAGS
variables should be used for both the fuzz
test and the software under test.
Don't overwrite CFLAGS
and CXXFLAGS
in your Makefile or included files, because CI Fuzz uses them for
instrumentation. If you need to set them, be sure to add your options instead:
CXXFLAGS += <your options>