Build a fuzzer
This guide assumes you have already created a fuzzer that you now want to build. It uses the same sample code as in that guide.
Fuchsia uses [GN][fuchsia-gn], a meta-build system, to generate .ninja files that explicitly
describe how to build the system. [GN targets][gn-targets] are nodes in the build graph that
represent a specific output such as a library or executable. GN templates are
rules that generate additional targets.
In order to make adding new fuzzers as easy as possible, Fuchsia provides fuzzing-related GN templates.
- To build a fuzzer binary, see Fuzzer GN template for the appropriate language.
- To assemble a package of fuzzer binaries, see Fuzzers package GN template.
Fuzzer GN template {#fuzzer}
Each language has a specific fuzzer GN template. All of these templates support certain common parameters, as detailed in [fuzzer.gni]:
- An optional [component manifest][glossary.component manifest source] (cmx) file. A manifest for fuzzing is always generated. If a
cmxfile is provided, it is combined with and overrides the generated file. - An optional [
dictionary][dictionary]. If not provided, an empty dictionary file is created. - An optional list of libFuzzer [
options]. These key-value pairs are written to a options file.
For example:
cpp_fuzzer("my-fuzzer") {
output_name = "the-fuzzer"
sources = [ "my_fuzzer.cc" ]
deps = [ ":my-lib" ]
dictionary = "my.dict"
cmx = "meta/the-fuzzer.cmx"
options = [
"key1=val1",
"key2=val2",
]
}
Each language has a specific fuzzer GN template:
- {C/C++}
The [
cpp_fuzzer][cpp_fuzzer.gni] GN template generates a GN target that compiles the fuzz target function and links it with the code under test and with libFuzzer.
To build a C or C++ fuzzer, add a cpp_fuzzer GN target to an appropriate BUILD.gn.
For example:
import("//build/cpp/cpp_fuzzer.gni")
cpp_fuzzer("parser-fuzzer") {
sources = [ "parser_fuzzer.cc" ]
deps = [ ":parser-lib" ]
}
- {Rust}
The [rustc_fuzzer][rustc_fuzzer.gni] GN template generates a GN target that compiles the Rust
fuzz target function into a C object file that it then links with libFuzzer.
To build a Rust fuzzer, add a rustc_fuzzer GN target to the crate's BUILD.gn.
When choosing where and how to add this target, consider the following:
-
It is recommended to have the fuzzer name match the fuzz target function name, and to include the fuzz target function in a Rust library, i.e. in
src/lib.rs. You may leave the body of the template empty when following these recommendations. For example, using thetoy_example_arbitraryexample, you would add the following to yourBUILD.gn: -
If the fuzz target function name differs from the fuzzer name, you must provide it with the
rustfunctionparameter. For example, using thetoy_example_u8example, you would add the following to yourBUILD.gn: -
If the code to be tested cannot be easily factored into a library, a Rust binary can be used with two additional steps:
- You must exclude the
mainfunction from compilation, along with any items not used when fuzzing, e.g. imports only used inmain. For example:
- You must explicitly provide the fuzz target function to the
rustc_fuzzerwith thesource_rootparameter. For example, in yourBUILD.gn:
- You must exclude the
-
{Go}
The [go_fuzzer][go_fuzzer.gni] GN template generates a GN target that compiles the Go fuzz
target function into a C object file that it then links with libFuzzer.
To build a Go fuzzer:
-
Ensure the Go package in the previous step is available as a
go_libraryGN target.For example:
-
Write a
go_fuzzerGN target to build the package containing the fuzz target function. Make sure to include thego_libraryindeps.For example:
When a [fuzzing variant][variants] is selected, these templates will build a fuzzer binary by linking the [libFuzzer] compiler runtime against code that provides a [fuzz target][fuzz-target] function.
Otherwise, a fuzzer unit test is built by linking a [test harness][test-harness] that calls the
fuzz target function with a zero length input against the provided sources, deps, or both. This
test ensures the fuzzer can compile and link, even when not building for fuzzing.
Note: Since the generated unit test uses a zero-length input, your fuzzer must not crash when provided with a zero-length input. If a fuzzer input is shorter than your fuzzer's minimum input length, you can simply return early.
Fuzzers package GN template {#fuzzers-package}
The fuzzers_package [template][fuzzer.gni] bundles fuzzers into a Fuchsia
[package][glossary.package] similar to how
a normal package bundles binaries or a test_package bundles tests. The fuzzers_package
template is distinguished from these other package templates in how it interacts with the currently
selected toolchain [variants].
Note: The Fuchsia build system will build the fuzzers only if their package is selected by a fuzzing variant. See Build fuzzers with fx.
The most important parameters to the template are the lists of fuzzers, organized by language.
For example:
fuzzers_package("my-fuzzers") {
cpp_fuzzers = [ ":my-cpp-fuzzer" ]
go_fuzzers = [ ":my-go-fuzzer" ]
rust_fuzzers = [ ":my-rust-fuzzer" ]
}
It is not necessary to include a list if the package has no fuzzers written in the corresponding languages.
A fuzzers_package can use all the same parameters as a [fuchsia_package][gn-package].
For example:
Additional parameters include:
fuzz_host: Also builds a fuzzer as a host tool (when selected). Defaults to false.host_only: Impliesfuzz_hostand does not create a Fuchsia package. Defaults to false.sanitizers: Sets the [sanitizers] to match during selection. Defaults to language-specific lists in [fuzzer.gni]. This typically does not need to be set.
For example:
The list of fuzzers can contain a mix of GN labels and scopes. Each scope element must include a label and can override the parameters above. Additionally, scopes can indicate output names for fuzzers that specify them.
For example:
fuzzers_package("my-fuzzers") {
cpp_fuzzers = [
{
label = ":my-fuzzer"
output_name = "the-fuzzer"
},
{
label = ":no-host-fuzzer"
fuzz_host = false
},
]
fuzz_host = true
}
Once defined, a package needs to be included in the build dependency graph like any other test package. This typically means adding it to a group of tests.
For example:
Build fuzzers with fx {#fx-set}
As noted above, the Fuchsia build system will build the fuzzers only if it is explicitly told to
instrument them for fuzzing with an appropriate fuzzing variant. These are the
[known variants][known_variants] that end in -fuzzer. Each one is an extension of a
[sanitizer][sanitizers] variant, including:
- asan: Use AddressSanitizer to detect memory errors such as memory usage after free or return, heap and stack buffer overflows, and more.
- ubsan: Use [UndefinedBehaviorSanitizer][ubsan] to detect behavior that violates the language specification such as signed integer overflow, misaligned pointers, and more.
- lsan: Use [LeakSanitizer][lsan] to detect memory leaks.
The easiest way to build a fuzzers_package with a fuzzing variant is to use the
--fuzz-with <sanitizer> flag with [fx set][fx-set].
For example:
fx set core.x64 --fuzz-with asan --with //bundles:testsfx build
Note: In some situations, Ninja cannot determine when an output needs to be rebuilt as a result of
compiler configuration changes. If building fails, try [fx clean-build][fx-build].
After running fx set, you can view the currently configured fuzzers with fx fuzz list.
Additional fx fuzz commands can be used to run a fuzzer.
[glossary.package](../../../glossary/README.md#package
cpp_fuzzer.gni[dictionary]: https://llvm.org/docs/LibFuzzer.html#dictionaries fuchsia-gn[fuzz-target]: https://llvm.org/docs/LibFuzzer.html#fuzz-target fuzzer.gnifx-build /development/build/fx.md#configure-a-build
gn-package[gn-targets]: https://gn.googlesource.com/gn/+/HEAD/docs/language.md#Targets
go_fuzzer.gniknown_variants https://clang.llvm.org/docs/LeakSanitizer.html
rustc_fuzzer.gni[sanitizers]: https://github.com/google/sanitizers/wiki test-harness[ubsan]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html