Skip to content

Commit d93363c

Browse files
authored
Update and simplify Jazzer integration (bazel-contrib#218)
* Update Jazzer to v0.17.1 * Add support for sanitizer runtimes * Refactor oss-fuzz support * Address review comments
1 parent 964d773 commit d93363c

14 files changed

+248
-256
lines changed

.bazelrc

+4
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
build --action_env=CC=clang-10
1717
build --action_env=CXX=clang++-10
1818

19+
# Workaround for https://github.com/bazelbuild/bazel/issues/3236
20+
build --sandbox_tmpfs_path=/tmp
21+
1922
# Strict dependency check for C++ includes.
2023
build --features=layering_check
2124

@@ -64,6 +67,7 @@ build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none
6467
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan
6568

6669
build:oss-fuzz --//fuzzing:cc_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_engine
70+
build:oss-fuzz --//fuzzing:java_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_java_engine
6771
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=oss-fuzz
6872
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=none
6973

README.md

+1-19
Original file line numberDiff line numberDiff line change
@@ -156,25 +156,7 @@ The crash is saved under `/tmp/fuzzing/artifacts` and can be further inspected.
156156

157157
### Java fuzzing
158158

159-
You can write `java_fuzz_test`s through the [Jazzer][jazzer-doc] fuzzing engine. You will need to enable it in your WORKSPACE `rules_fuzzing_dependencies` call:
160-
161-
```python
162-
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
163-
164-
rules_fuzzing_dependencies(jazzer = True)
165-
166-
load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
167-
168-
rules_fuzzing_init()
169-
170-
load("@jazzer//:repositories.bzl", "jazzer_dependencies")
171-
172-
jazzer_dependencies()
173-
174-
load("@jazzer//:init.bzl", "jazzer_init")
175-
176-
jazzer_init()
177-
```
159+
You can write `java_fuzz_test`s through the [Jazzer][jazzer-doc] fuzzing engine.
178160

179161
To use Jazzer, it is convenient to also define a `.bazelrc` configuration, similar to the C++ libFuzzer one above:
180162

WORKSPACE

+1-9
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
2020

2121
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
2222

23-
rules_fuzzing_dependencies(jazzer = True)
23+
rules_fuzzing_dependencies()
2424

2525
load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
2626

@@ -30,14 +30,6 @@ load("@fuzzing_py_deps//:requirements.bzl", "install_deps")
3030

3131
install_deps()
3232

33-
load("@jazzer//:repositories.bzl", "jazzer_dependencies")
34-
35-
jazzer_dependencies()
36-
37-
load("@jazzer//:init.bzl", "jazzer_init")
38-
39-
jazzer_init()
40-
4133
# The support for running the examples and unit tests.
4234

4335
http_archive(

fuzzing/engines/BUILD

+11-1
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,16 @@ java_fuzzing_engine(
6868
name = "jazzer",
6969
display_name = "Jazzer",
7070
launcher = "jazzer_launcher.sh",
71-
library = "@jazzer//agent:jazzer_api_compile_only",
71+
library = ":jazzer_stub",
7272
visibility = ["//visibility:public"],
7373
)
74+
75+
# This wrapper target is needed as Jazzer consists of two separate Java targets,
76+
# but java_fuzzing_engine's library attribute only accepts a single target.
77+
java_library(
78+
name = "jazzer_stub",
79+
exports = [
80+
"@rules_fuzzing_jazzer//jar",
81+
"@rules_fuzzing_jazzer_api//jar",
82+
],
83+
)

fuzzing/private/BUILD

+7-15
Original file line numberDiff line numberDiff line change
@@ -29,36 +29,28 @@ exports_files([
2929
"util.bzl",
3030
])
3131

32-
# Config settings needed for prebuilt engines.
3332
config_setting(
34-
name = "use_sanitizer_none",
33+
name = "is_oss_fuzz",
3534
flag_values = {
36-
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
35+
"@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
3736
},
37+
visibility = ["//visibility:public"],
3838
)
3939

4040
config_setting(
41-
name = "use_sanitizer_asan",
41+
name = "use_asan",
4242
flag_values = {
4343
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "asan",
4444
},
45+
visibility = ["//visibility:public"],
4546
)
4647

4748
config_setting(
48-
name = "use_sanitizer_ubsan",
49+
name = "use_ubsan",
4950
flag_values = {
5051
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "ubsan",
5152
},
52-
)
53-
54-
config_setting(
55-
name = "use_oss_fuzz",
56-
flag_values = {
57-
"@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
58-
# This is required to make the setting an unambiguous specialization of
59-
# the use_sanitizer_* settings.
60-
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
61-
},
53+
visibility = ["//visibility:public"],
6254
)
6355

6456
exports_files([

fuzzing/private/fuzz_test.bzl

+54-33
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
"""The implementation of the {cc, java}_fuzz_test rules."""
1616

17+
load("@rules_fuzzing_oss_fuzz//:instrum.bzl", "native_library_sanitizer")
1718
load("@rules_cc//cc:defs.bzl", "cc_binary")
1819

1920
# FIXME: Including this leads to a Stardoc error since defs.bzl is not visible. As a workaround, use native.java_binary.
@@ -213,6 +214,15 @@ def cc_fuzz_test(
213214
test_timeout = timeout,
214215
)
215216

217+
_ASAN_RUNTIME = Label("//fuzzing/private/runtime:asan")
218+
_UBSAN_RUNTIME = Label("//fuzzing/private/runtime:ubsan")
219+
_RUNTIME_BY_NAME = {
220+
"asan": _ASAN_RUNTIME,
221+
"ubsan": _UBSAN_RUNTIME,
222+
"none": None,
223+
}
224+
225+
# buildifier: disable=list-append
216226
def java_fuzz_test(
217227
name,
218228
srcs = None,
@@ -264,6 +274,8 @@ def java_fuzz_test(
264274
# this target directly. Instead, the binary should be built through the
265275
# instrumented configuration.
266276
raw_target_name = name + "_target_"
277+
metadata_binary_name = name + "_metadata_"
278+
metadata_deploy_jar_name = metadata_binary_name + "_deploy.jar"
267279

268280
# Determine a value for target_class heuristically using the same rules as
269281
# those used by Bazel internally for main_class.
@@ -277,62 +289,71 @@ def java_fuzz_test(
277289
name = name,
278290
))
279291
target_class_manifest_line = "Jazzer-Fuzz-Target-Class: %s" % target_class
280-
binary_kwargs.setdefault("deps", [])
281292

282-
# Use += rather than append to allow users to pass in select() expressions for
283-
# deps, which only support concatenation with +.
284-
# Workaround for https://github.com/bazelbuild/bazel/issues/14157.
285-
# buildifier: disable=list-append
286-
binary_kwargs["deps"] += [engine]
287-
binary_kwargs.setdefault("deploy_manifest_lines", [])
293+
native.java_binary(
294+
name = metadata_binary_name,
295+
deploy_manifest_lines = [target_class_manifest_line],
296+
tags = ["manual"],
297+
)
288298

289-
# buildifier: disable=list-append
290-
binary_kwargs["deploy_manifest_lines"] += [target_class_manifest_line]
299+
# use += rather than append to allow users to pass in select() expressions for
300+
# deps, which only support concatenation with +.
301+
# workaround for https://github.com/bazelbuild/bazel/issues/14157.
302+
if srcs:
303+
binary_kwargs.setdefault("deps", [])
304+
binary_kwargs["deps"] += [engine, metadata_deploy_jar_name]
305+
else:
306+
binary_kwargs.setdefault("runtime_deps", [])
307+
binary_kwargs["runtime_deps"] += [engine, metadata_deploy_jar_name]
308+
309+
binary_kwargs.setdefault("jvm_flags", [])
310+
binary_kwargs["jvm_flags"] = [
311+
# Ensures that full stack traces are emitted for findings even in highly
312+
# optimized code.
313+
"-XX:-OmitStackTraceInFastThrow",
314+
# Optimized for throughput rather than latency.
315+
"-XX:+UseParallelGC",
316+
# Ignore CriticalJNINatives if not available (JDK 18+).
317+
"-XX:+IgnoreUnrecognizedVMOptions",
318+
# Improves performance of Jazzer's native compare instrumentation.
319+
"-XX:+CriticalJNINatives",
320+
] + binary_kwargs["jvm_flags"]
291321

292322
# tags is not configurable and can thus use append.
293323
binary_kwargs.setdefault("tags", []).append("manual")
294324
native.java_binary(
295325
name = raw_target_name,
296326
srcs = srcs,
297-
create_executable = False,
327+
main_class = "com.code_intelligence.jazzer.Jazzer",
298328
**binary_kwargs
299329
)
300330

301331
raw_binary_name = name + "_raw_"
302332
jazzer_fuzz_binary(
303333
name = raw_binary_name,
304-
agent = select({
305-
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_agent_deploy.jar",
306-
"//conditions:default": "@jazzer//agent:jazzer_agent_deploy.jar",
334+
sanitizer = select({
335+
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": native_library_sanitizer,
336+
"@rules_fuzzing//fuzzing/private:use_asan": "asan",
337+
"@rules_fuzzing//fuzzing/private:use_ubsan": "ubsan",
338+
"//conditions:default": "none",
307339
}),
308-
# Since the choice of sanitizer is explicit for local fuzzing, we also
309-
# let it apply to projects with no native dependencies.
310-
driver_java_only = select({
311-
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver",
312-
"@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
313-
"@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
314-
"@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
315-
}, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
316-
driver_with_native = select({
317-
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver_with_sanitizer",
318-
"@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
319-
"@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
320-
"@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
321-
}, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
322340
sanitizer_options = select({
323-
"@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh",
324-
"//conditions:default": "@rules_fuzzing//fuzzing/private:local_jazzer_sanitizer_options.sh",
341+
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": Label("//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh"),
342+
"//conditions:default": Label("//fuzzing/private:local_jazzer_sanitizer_options.sh"),
343+
}),
344+
sanitizer_runtime = select({
345+
"@rules_fuzzing//fuzzing/private:is_oss_fuzz": _RUNTIME_BY_NAME[native_library_sanitizer],
346+
"@rules_fuzzing//fuzzing/private:use_asan": _ASAN_RUNTIME,
347+
"@rules_fuzzing//fuzzing/private:use_ubsan": _UBSAN_RUNTIME,
348+
"//conditions:default": None,
325349
}),
326-
tags = ["manual"],
327350
target = raw_target_name,
328-
target_deploy_jar = raw_target_name + "_deploy.jar",
351+
tags = ["manual"],
329352
)
330353

331354
fuzzing_decoration(
332355
name = name,
333356
raw_binary = raw_binary_name,
334-
# jazzer_fuzz_binary already instrumented the native dependencies.
335-
instrument_binary = False,
336357
engine = engine,
337358
corpus = corpus,
338359
dicts = dicts,

0 commit comments

Comments
 (0)