blob: adc7286379be01e055db6c900ba92dd0e47b9d1f [file] [log] [blame] [view]
Filip Niksica63c5f12022-09-28 14:38:55 -07001# Quickstart with Bazel
2
3This tutorial describes how to set up your development environment with Bazel as
4the build system, and how to get a simple fuzz test up and running. We recommend
5this tutorial if you're new to FuzzTest or if you need a quick refresher. For a
6more extensive showcase of the FuzzTest framework, consider doing the
7[Codelab](tutorial.md).
8
9## Prerequisites
10
11To use FuzzTest, you'll need:
12
13* A Linux-based operating system
14* [Clang](https://clang.llvm.org/)
15* [Bazel](https://bazel.build/)
16
17## Set up a Bazel workspace
18
19First, create a directory where your project will reside:
20
21```sh
22$ mkdir -p my_workspace && cd my_workspace
23```
24
25In this directory, create a file named `WORKSPACE` to define a
26[Bazel workspace](https://bazel.build/concepts/build-ref#workspace). The file
27will configure FuzzTest along with its transitive dependencies as Bazel external
28dependencies:
29
30```
Filip Niksica63c5f12022-09-28 14:38:55 -070031load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
32
33################################################################################
34# Direct dependencies
35################################################################################
36
László Szekeres052999a2022-10-03 09:02:43 -070037# To use the latest version of FuzzTest, update this regularly to the latest
38# commit in the main branch: https://github.com/google/fuzztest/commits/main
39FUZZTEST_COMMIT = "62cf00c7341eb05d128d0a3cbce79ac31dbda032"
40
41http_archive(
Filip Niksica63c5f12022-09-28 14:38:55 -070042 name = "com_google_fuzztest",
László Szekeres052999a2022-10-03 09:02:43 -070043 strip_prefix = "fuzztest-" + FUZZTEST_COMMIT,
44 url = "https://github.com/google/fuzztest/archive/" + FUZZTEST_COMMIT + ".zip",
Filip Niksica63c5f12022-09-28 14:38:55 -070045)
46
47http_archive(
48 name = "com_google_googletest",
49 sha256 = "81964fe578e9bd7c94dfdb09c8e4d6e6759e19967e397dbea48d1c10e45d0df2",
50 strip_prefix = "googletest-release-1.12.1",
51 url = "https://github.com/google/googletest/archive/refs/tags/release-1.12.1.tar.gz",
52)
53
54################################################################################
55# Transitive dependencies
56################################################################################
57
58# Required by com_google_fuzztest.
59http_archive(
60 name = "com_googlesource_code_re2",
61 sha256 = "f89c61410a072e5cbcf8c27e3a778da7d6fd2f2b5b1445cd4f4508bee946ab0f",
62 strip_prefix = "re2-2022-06-01",
63 url = "https://github.com/google/re2/archive/refs/tags/2022-06-01.tar.gz",
64)
65
66# Required by com_google_fuzztest.
67http_archive(
68 name = "com_google_absl",
Xinhao Yuan3c2a14c2023-04-17 20:25:03 -070069 sha256 = "3ea49a7d97421b88a8c48a0de16c16048e17725c7ec0f1d3ea2683a2a75adc21",
70 strip_prefix = "abseil-cpp-20230125.0",
71 url = "https://github.com/abseil/abseil-cpp/archive/refs/tags/20230125.0.tar.gz",
Filip Niksica63c5f12022-09-28 14:38:55 -070072)
73
74# Required by com_google_absl.
75http_archive(
76 name = "bazel_skylib",
77 sha256 = "f7be3474d42aae265405a592bb7da8e171919d74c16f082a5457840f06054728",
78 urls = [
79 "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz",
80 "https://github.com/bazelbuild/bazel-skylib/releases/download/1.2.1/bazel-skylib-1.2.1.tar.gz",
81 ],
82)
83```
84
85NOTE: We recommend the users to "live at head," that is, to often update the
86`com_google_fuzztest` repository to the latest commit from the main branch.
87
88NOTE: It is possible to use FuzzTest without GoogleTest, and thus without
89depending on `com_google_googletest`, but this is beyond the scope of this
90tutorial.
91
92Next, create a [Bazel configuration file](https://bazel.build/run/bazelrc) named
93`.bazelrc` to configure the build flags:
94
95```
96# Force the use of Clang for all builds. FuzzTest relies on Clang for sanitizer
97# coverage (https://clang.llvm.org/docs/SanitizerCoverage.html).
98build --action_env=CC=clang
99build --action_env=CXX=clang++
100
101# Use the C++17 standard.
102build --cxxopt=-std=c++17
103
Filip Niksica63c5f12022-09-28 14:38:55 -0700104# Show everything when running tests.
105test --test_output=streamed
106
107# To create this file, please run:
108#
109# bazel run @com_google_fuzztest//bazel:setup_configs > fuzztest.bazelrc
110#
111try-import %workspace%/fuzztest.bazelrc
112```
113
114As suggested by the comments, generate a file named `fuzztest.bazelrc` with
115additional build configurations. We generate the file using a script from the
116FuzzTest repo to make sure it contains the correct and recent settings:
117
118```sh
119$ bazel run @com_google_fuzztest//bazel:setup_configs > fuzztest.bazelrc
120```
121
122## Create and run a fuzz test
123
124With the Bazel workspace set up, you can start using FuzzTest. Let's create a
125trivial example to make sure everything runs correctly.
126
127Create a file named `first_fuzz_test.cc` in the directory `my_workspace` with
128the following contents:
129
130```c++
131#include "fuzztest/fuzztest.h"
132#include "gtest/gtest.h"
133
134TEST(MyTestSuite, OnePlustTwoIsTwoPlusOne) {
135 EXPECT_EQ(1 + 2, 2 + 1);
136}
137
138void IntegerAdditionCommutes(int a, int b) {
139 EXPECT_EQ(a + b, b + a);
140}
141FUZZ_TEST(MyTestSuite, IntegerAdditionCommutes);
142```
143
144The file contains two tests in the test suite named `MyTestSuite`. The first one
145is a unit test named `OnePlustTwoIsTwoPlusOne` asserting that integer addition
146commutes for two specific values.
147
148The second test is a fuzz test that captures the commutative property of integer
149addition more generally. The test consists of a property function with a
150suggestive name `IntegerAdditionCommutes`, and the test registration using the
151macro `FUZZ_TEST`. The property function asserts the commutative property for
152two generic integer parameters.
153
154To build and run the tests, create a file named `BUILD` with the following
155contents:
156
157```
158cc_test(
159 name = "first_fuzz_test",
160 srcs = ["first_fuzz_test.cc"],
161 deps = [
162 "@com_google_fuzztest//fuzztest",
163 "@com_google_fuzztest//fuzztest:fuzztest_gtest_main",
164 "@com_google_googletest//:gtest"
165 ],
166)
167```
168
169This defines a C++ test binary and links it with the FuzzTest and GoogleTest
170libraries, as well as the version of the default GoogleTest main that supports
171FuzzTest.
172
173There are two ways to run the tests: in the unit test mode and in the fuzzing
174mode. The unit test mode runs both test for a short time without sanitizer and
175coverage instrumentation:
176
177```
178$ bazel test :first_fuzz_test
179
180WARNING: Streamed test output requested. All tests will be run locally, without sharding, one at a time
181INFO: Analyzed target //:first_fuzz_test (71 packages loaded, 1231 targets configured).
182INFO: Found 1 test target...
183[==========] Running 2 tests from 1 test suite.
184[----------] Global test environment set-up.
185[----------] 2 tests from MyTestSuite
186[ RUN ] MyTestSuite.OnePlustTwoIsTwoPlusOne
187[ OK ] MyTestSuite.OnePlustTwoIsTwoPlusOne (0 ms)
188[ RUN ] MyTestSuite.IntegerAdditionCommutes
189[ OK ] MyTestSuite.IntegerAdditionCommutes (13 ms)
190[----------] 2 tests from MyTestSuite (13 ms total)
191
192[----------] Global test environment tear-down
193[==========] 2 tests from 1 test suite ran. (13 ms total)
194[ PASSED ] 2 tests.
195Target //:first_fuzz_test up-to-date:
196 bazel-bin/first_fuzz_test
197INFO: Elapsed time: 14.089s, Critical Path: 4.54s
198INFO: 488 processes: 262 internal, 226 linux-sandbox.
199INFO: Build completed successfully, 488 total actions
200//:first_fuzz_test PASSED in 0.1s
201
202Executed 1 out of 1 test: 1 test passes.
203INFO: Build completed successfully, 488 total actions
204```
205
206The fuzzing mode runs a single specified fuzz test with sanitizer and coverage
207instrumentation. It keeps running the test with different input values until it
208finds a crash or it is explicitly terminated by the user:
209
210```
211$ bazel run --config=fuzztest :first_fuzz_test -- \
212 --fuzz=MyTestSuite.IntegerAdditionCommutes
213
214INFO: Build options --copt, --dynamic_mode, --linkopt, and 1 more have changed, discarding analysis cache.
215INFO: Analyzed target //:first_fuzz_test (0 packages loaded, 1231 targets configured).
216INFO: Found 1 target...
217Target //:first_fuzz_test up-to-date:
218 bazel-bin/first_fuzz_test
219INFO: Elapsed time: 14.570s, Critical Path: 5.11s
220INFO: 161 processes: 4 internal, 157 linux-sandbox.
221INFO: Build completed successfully, 161 total actions
222INFO: Build completed successfully, 161 total actions
223exec ${PAGER:-/usr/bin/less} "$0" || exit 1
224Executing tests from //:first_fuzz_test
225-----------------------------------------------------------------------------
226[.] Sanitizer coverage enabled. Counter map size: 21290, Cmp map size: 262144
227Note: Google Test filter = MyTestSuite.IntegerAdditionCommutes
228[==========] Running 1 test from 1 test suite.
229[----------] Global test environment set-up.
230[----------] 1 test from MyTestSuite
231[ RUN ] MyTestSuite.IntegerAdditionCommutes
232[*] Corpus size: 1 | Edges covered: 131 | Fuzzing time: 504.798us | Total runs: 1.00e+00 | Runs/secs: 1
233[*] Corpus size: 2 | Edges covered: 133 | Fuzzing time: 934.176us | Total runs: 3.00e+00 | Runs/secs: 3
234[*] Corpus size: 3 | Edges covered: 134 | Fuzzing time: 2.384383ms | Total runs: 5.30e+01 | Runs/secs: 53
235[*] Corpus size: 4 | Edges covered: 137 | Fuzzing time: 2.732274ms | Total runs: 5.40e+01 | Runs/secs: 54
236[*] Corpus size: 5 | Edges covered: 137 | Fuzzing time: 7.275553ms | Total runs: 2.48e+02 | Runs/secs: 248
237[*] Corpus size: 6 | Edges covered: 137 | Fuzzing time: 21.97155ms | Total runs: 9.12e+02 | Runs/secs: 912
238[*] Corpus size: 7 | Edges covered: 137 | Fuzzing time: 166.721522ms | Total runs: 8.49e+03 | Runs/secs: 8491
239[*] Corpus size: 8 | Edges covered: 146 | Fuzzing time: 500.398497ms | Total runs: 2.77e+04 | Runs/secs: 27741
240[*] Corpus size: 9 | Edges covered: 146 | Fuzzing time: 500.821386ms | Total runs: 2.77e+04 | Runs/secs: 27742
241[*] Corpus size: 10 | Edges covered: 147 | Fuzzing time: 2.597553524s | Total runs: 1.75e+05 | Runs/secs: 87476
242^C
243```
244
245Congratulations! You're now all set for fuzzing with FuzzTest.
246
247## Next steps
248
249* This tutorial covered the basic setup of the build environment with Bazel.
250 To learn more about the FuzzTest framework and how to use it, check out the
251 [Codelab](tutorial.md).
252* Explore the rest of the [documentation](./).