blob: 0660369ed2e22c858f854315e4a2e5f33120fe56 [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]{: .external} are nodes in the build graph
that represent a specific output such as a library or executable.
[_GN templates_][gn-templates]{: .external} are rules that generate additional targets.
In order to make adding new fuzzers as easy as possible, Fuchsia provides fuzzing-related GN
templates.
* To create build rules for a fuzzer binary for Fuchsia, see the
[Fuchsia library fuzzer GN template](#fuchsia-library-fuzzer) for the appropriate language.
* To create build rules for a fuzzer binary for your development host, see the
[Host library fuzzer GN template](#host-library-fuzzer)
* To create build rules for a fuzzer component, see
[Fuchsia fuzzer component GN template](#fuchsia-fuzzer-component).
* To create build rules for a package of fuzzer binaries, see
[Fuchsia fuzzer package GN template](#fuchsia-fuzzer-package).
Once you have defined your build rules, you can [build fuzzers with fx](#fx-set).
## Fuchsia library fuzzer GN template {#fuchsia-library-fuzzer}
Each language has a specific fuzzer GN template:
* {C/C++}
The [`fuchsia_library_fuzzer`][fuchsia_library_fuzzer.gni] GN template generates an `executable`
target that compiles and links the fuzz target function with the code under test and the fuzzing
engine.
To create build rules for a C or C++ fuzzer, add a `fuchsia_library_fuzzer` GN target to an
appropriate BUILD.gn, such as the one with the corresponding unit test rules.
For example:
```gn
import("//build/fuzz.gni")
fuchsia_library_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 the fuzzing engine.
To create build rules for 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`:
```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`:
```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`:
```gn
import("//build/rust/rustc_fuzzer.gni")
rustc_fuzzer("toy_example_with_main") {
source_root = "src/main.rs"
}
```
When a [fuzzing variant][variants] is [selected](#fx-set), these templates will build a fuzzer
binary by linking the \[libFuzzer\] compiler runtime with the provided `sources`, `deps` or both. This
code must provide a [fuzz target][fuzz-target]{:.external} function.
Otherwise, a fuzzer unit test is built by linking a [test harness][test-harness] with the provided
code. This test harness calls the fuzz target function with fixed inputs, such
as a zero length input. 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.
## Host library fuzzer GN template {#host-library-fuzzer}
You can also build fuzzers that run on your development host using the Fuchsia build system.
To build host fuzzers, use the [`host_library_fuzzer`][host_library_fuzzer.gni] GN template.
For example:
```gn
host_library_fuzzer("my_host_fuzzer") {
sources = [ ... ]
deps = [ ... ]
}
```
Host fuzzers can be built using [`fx`](#fx-set) without adding them to a Fuchsia component or
package.
## Fuchsia fuzzer component GN template {#fuchsia-fuzzer-component}
The `fuchsia_fuzzer_component` [template][fuchsia_fuzzer_component.gni] creates a component used to
run the fuzzer. It can include the usual component parameters, such as `component_name` and `deps`.
For example:
```gn
fuchsia_fuzzer_component("my-fuzzer-component") {
component_name = "my-fuzzer"
manifest = "meta/my-fuzzer.cml"
deps = [ ":my-corpus"]
}
```
The [component manifest source][glossary.manifest] for library fuzzers must include
the default shard for libfuzzer. The output name of the fuzzer must be
provided as the first program argument as a package-relative path. Additional arguments may include
libFuzzer [options][options]{:.external}, or package-relative paths to directories of seed inputs
known as [seed corpora][corpus]{:.external}.
For example:
```
{
include: [
"//sdk/lib/inspect/client.shard.cml",
"//src/sys/fuzzing/libfuzzer/default.shard.cml",
"//src/sys/test_runners/fuzz/default.shard.cml",
"//src/sys/test_runners/tmp_storage.shard.cml",
"syslog/client.shard.cml",
]
program: {
args: [
"test/my-fuzzer",
"-max_input_size=256",
"data/my-corpus",
]
}
}
```
A seed corpus should match a `resource` target that is included in the component's
`deps`.
For example:
```gn
{% verbatim %}
import("//build/dist/resource.gni")
resource("my-corpus") {
sources = [
"input0",
"input1",
"input2",
]
outputs = [ "data/my-corpus/{{source_file_part}}" ]
}
{% endverbatim %}
```
## Fuchsia fuzzer package GN template {#fuchsia-fuzzer-package}
The `fuchsia_fuzzer_package` [template][fuzzer_package.gni] bundles fuzzer components into a
Fuchsia [package][glossary.package], similar to how `fuchsia_test_package` bundles test components.
The `fuchsia_fuzzer_package` template is distinguished by adding a specific build rule
to annotate fuzzers when built by a fuzzing toolchain [variant][variants].
Note: Executables built by these templates are only be capable of fuzzing if they are selected by a
fuzzing toolchain variant. If they are built by another toolchain, they only test a fixed set of
inputs. See [Build fuzzers with fx](#fx-set) for more details.
The template includes parameters that are lists of fuzzer components, organized by language. Each
language has a set of supported sanitizers provided by their toolchain as compiler runtimes.
When the selected toolchain variant includes a sanitizer that is supported for a given language, the
corresponding list of fuzzer components are capable of fuzzing.
For example, if the C++ toolchain has support for a hypotheical _examplesan_, the Rust toolchain
does not, and the _examplesan-fuzzer_ variant is selected, then the package definition below builds
`my-cpp-fuzzer` for fuzzing and `my-rust-fuzzer` for testing only.
```gn
fuchsia_fuzzer_package("my-fuzzers") {
cpp_fuzz_components = [ ":my-cpp-fuzzer" ]
rust_fuzz_components = [ ":my-rust-fuzzer" ]
}
```
It is not necessary to include a list if the package has no fuzzers written in the corresponding
languages.
A `fuchsia_fuzzer_package` can use all the same parameters as a [`fuchsia_package`][gn-package].
For example:
```gn
fuchsia_fuzzer_package("my-fuzzers") {
package_name = "the-fuzzers"
cpp_fuzz_components = [ ":my-fuzzer" ]
}
```
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:
```gn
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]{:.external} variant, including:
* _asan_: Use [AddressSanitizer][asan]{:.external} to detect memory errors such as using memory
after [freeing][asan-uaf]{:.external} or [returning][asan-uar]{:.external} it, overflowing
[heap][asan-hbo]{:.external} and [stack][asan-sbo]{:.external} buffer overflows, and more.
* _ubsan_: Use [UndefinedBehaviorSanitizer][ubsan]{:.external} to detect behavior that violates the
language specification such as [signed integer overflow][ubsan-sio]{:.external}, misaligned
pointers, and [more][ubsan-all]{:.external}.
The easiest way to build a `fuzzer_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 `ffx fuzz list`.
Additional `ffx fuzz` commands can be used to [run a fuzzer](run-a-fuzzer.md).
[glossary.package]: /docs/glossary/README.md#package
[glossary.manifest]: /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
[corpus]: https://llvm.org/docs/LibFuzzer.html#corpus
[fuchsia-gn]: /docs/development/build/build_system/intro.md
[fuchsia_library_fuzzer.gni]: /build/fuzzing/fuchsia_library_fuzzer.gni
[fuchsia_fuzzer_component.gni]: /build/fuzzing/fuchsia_fuzzer_component.gni
[fuzz-target]: https://llvm.org/docs/LibFuzzer.html#fuzz-target
[fuzzer_package.gni]: /build/fuzzing/fuchsia_fuzzer_package.gni
[fx-build]: /docs/development/build/fx.md#execute-a-build
[fx-set]: /docs/development/build/fx.md#configure-a-build
[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
[host_library_fuzzer.gni]: /build/fuzzing/host_library_fuzzer.gni
[known_variants]: /docs/gen/build_arguments.md#known_variants
[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