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.
You can configure one-time setup required by the FUZZ_TEST
in FUZZ_TEST_SETUP()
.
FuzzedDataProvider
While not required, it's 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 use 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 you want to test, just as you would for a unit test.
Integrate a fuzz test into your project
Depending on your build system, you need to follow the next steps 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 to use for the fuzz test and the SUT
- CXXFLAGS - Sets the necessary C++ compiler and linker flags to use for the fuzz test and the SUT
- FUZZ_TEST_CFLAGS - Sets the necessary compiler flags to use for the fuzz test
- FUZZ_TEST_LD_FLAGS - Sets the necessary linker flags to use for the fuzz test
You must pass the environment variables FUZZ_TEST_CFLAGS
and FUZZ_TEST_LDFLAGS
to the compiler and
linker command for the fuzz test. Use the CC
and CFLAGS
/CXX
and CXXFLAGS
for both the fuzz
test and the SUT.
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>