blob: be453e84910c33c7874f8b2510232505a1492f29 [file] [log] [blame] [view]
# Build a fuzzer
This guide assumes you have already [created](write-a-fuzzer.md) a fuzzer that you now want to
build. It uses the same [sample code](write-a-fuzzer.md#samples) 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_][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](#fuzzer) for the appropriate language.
* To assemble a package of fuzzer binaries, see [Fuzzers package GN template](#fuzzers-package).
## 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
`cmx` file 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 the
`toy_example_arbitrary` [example](write-a-fuzzer.md#advanced), you would add the following to
your `BUILD.gn`:
```
import("//build/rust/rustc_fuzzer.gni")
rustc_fuzzer("toy_example_arbitrary") {
}
```
* If the fuzz target function name differs from the fuzzer name, you must provide it with the
`rustfunction` parameter. For example, using the `toy_example_u8`
[example](write-a-fuzzer.md#basic), you would add the following to your `BUILD.gn`:
```
import("//build/rust/rustc_fuzzer.gni")
rustc_fuzzer("toy_example_raw_bytes") {
rustfunction = "toy_example_u8"
}
```
* 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 `main` function from compilation, along with any items not used when
fuzzing, e.g. imports only used in `main`. For example:
```rust
#[cfg(not(fuzz))]
use only::used::in::main;
#[cfg(not(fuzz))]
fn main() { ... }
```
* You must explicitly provide the fuzz target function to the `rustc_fuzzer` with the
`source_root` parameter. For example, in your `BUILD.gn`:
```
import("//build/rust/rustc_fuzzer.gni")
rustc_fuzzer("toy_example_with_main") {
source_root = "src/main.rs"
}
```
* {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:
1. Ensure the Go package in the [previous step](#write) is available as a `go_library` GN target.
For example:
```
import("//build/go/go_library.gni")
go_library("my_library") {
sources = "pkg/file_with_fuzz.go"
}
```
1. Write a `go_fuzzer` GN target to build the package containing the fuzz target function. Make
sure to include the `go_library` in [`deps`][gn-deps].
For example:
```
import("//build/go/go_fuzzer.gni")
go_fuzzer("my_fuzzer") {
gopackage = "my_library/pkg"
deps = [ ":my_library" ]
}
```
When a [fuzzing variant][variants] is [selected](#fx-set), 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](#fx-set).
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:
```
fuzzers_package("my-fuzzers") {
package_name = "the-fuzzers"
cpp_fuzzers = [ ":my-fuzzer" ]
}
```
Additional parameters include:
* `fuzz_host`: Also builds a fuzzer as a host tool (when [selected](#variant-selection)). Defaults
to false.
* `host_only`: Implies `fuzz_host` and does not create a Fuchsia package. Defaults to false.
* `sanitizers`: Sets the [sanitizers] to match during [selection](#variant-selection). Defaults to
language-specific lists in [fuzzer.gni]. This typically does not need to be set.
For example:
```
fuzzers_package("my-fuzzers") {
cpp_fuzzers = [ ":my-fuzzer" ]
fuzz_host = true
}
```
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:
```
group("tests") {
deps = [
":my-test-package",
":my-fuzzers",
]
}
```
## 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][asan] to detect memory errors such as memory usage after
[free][asan-uaf] or [return][asan-uar], [heap][asan-hbo] and [stack][asan-sbo] buffer overflows,
and more.
* _ubsan_: Use [UndefinedBehaviorSanitizer][ubsan] to detect behavior that violates the language
specification such as [signed integer overflow][ubsan-sio], misaligned pointers, and
[more][ubsan-all].
* _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:
<pre>
<code class="devsite-terminal">fx set core.x64 --fuzz-with asan --with //bundles:tests</code>
<code class="devsite-terminal">fx build</code>
</pre>
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](run-a-fuzzer.md).
[glossary.package]: /docs/glossary/README.md#package
[glossary.component manifest source]: /docs/glossary/README.md#component-manifest-source
[asan]: https://clang.llvm.org/docs/AddressSanitizer.html
[asan-hbo]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleHeapOutOfBounds
[asan-sbo]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleStackOutOfBounds
[asan-uaf]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleUseAfterFree
[asan-uar]: https://github.com/google/sanitizers/wiki/AddressSanitizerExampleUseAfterReturn
[cpp_fuzzer.gni]: /build/cpp/cpp_fuzzer.gni
[dictionary]: https://llvm.org/docs/LibFuzzer.html#dictionaries
[fuchsia-gn]: /docs/development/build/build_system/intro.md
[fuzz-target]: https://llvm.org/docs/LibFuzzer.html#fuzz-target
[fuzzer.gni]: /build/fuzzing/fuzzer.gni
[fx-build]: /docs/development/build/fx.md#execute-a-build
[fx-set]: /docs/development/build/fx.md#configure-a-build
[gn-deps]: https://gn.googlesource.com/gn/+/HEAD/docs/reference.md#var_deps
[gn-package]: /docs/development/components/build.md
[gn-targets]: https://gn.googlesource.com/gn/+/HEAD/docs/language.md#Targets
[gn-templates]: https://gn.googlesource.com/gn/+/HEAD/docs/language.md#Templates
[go_fuzzer.gni]: /build/go/go_fuzzer.gni
[known_variants]: /docs/gen/build_arguments.md#known_variants
[lsan]: https://clang.llvm.org/docs/LeakSanitizer.html
[options]: https://llvm.org/docs/LibFuzzer.html#options
[rustc_fuzzer.gni]: /build/rust/rustc_fuzzer.gni
[sanitizers]: https://github.com/google/sanitizers/wiki
[test-harness]: /src/lib/fuzzing/cpp/fuzzer_test.cc
[ubsan]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
[ubsan-sio]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#usage
[ubsan-all]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html#available-checks
[variants]: /docs/development/build/build_system/variants.md