Update and simplify Jazzer integration (#218)
* Update Jazzer to v0.17.1
* Add support for sanitizer runtimes
* Refactor oss-fuzz support
* Address review comments
diff --git a/.bazelrc b/.bazelrc
index ebe78ed..5623e30 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -16,6 +16,9 @@
build --action_env=CC=clang-10
build --action_env=CXX=clang++-10
+# Workaround for https://github.com/bazelbuild/bazel/issues/3236
+build --sandbox_tmpfs_path=/tmp
+
# Strict dependency check for C++ includes.
build --features=layering_check
@@ -64,6 +67,7 @@
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan
build:oss-fuzz --//fuzzing:cc_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_engine
+build:oss-fuzz --//fuzzing:java_engine=@rules_fuzzing_oss_fuzz//:oss_fuzz_java_engine
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=oss-fuzz
build:oss-fuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=none
diff --git a/README.md b/README.md
index c3fd6e3..0aa2822 100644
--- a/README.md
+++ b/README.md
@@ -156,25 +156,7 @@
### Java fuzzing
-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:
-
-```python
-load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
-
-rules_fuzzing_dependencies(jazzer = True)
-
-load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
-
-rules_fuzzing_init()
-
-load("@jazzer//:repositories.bzl", "jazzer_dependencies")
-
-jazzer_dependencies()
-
-load("@jazzer//:init.bzl", "jazzer_init")
-
-jazzer_init()
-```
+You can write `java_fuzz_test`s through the [Jazzer][jazzer-doc] fuzzing engine.
To use Jazzer, it is convenient to also define a `.bazelrc` configuration, similar to the C++ libFuzzer one above:
diff --git a/WORKSPACE b/WORKSPACE
index 14d26a2..e893f5c 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -20,7 +20,7 @@
load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
-rules_fuzzing_dependencies(jazzer = True)
+rules_fuzzing_dependencies()
load("@rules_fuzzing//fuzzing:init.bzl", "rules_fuzzing_init")
@@ -30,14 +30,6 @@
install_deps()
-load("@jazzer//:repositories.bzl", "jazzer_dependencies")
-
-jazzer_dependencies()
-
-load("@jazzer//:init.bzl", "jazzer_init")
-
-jazzer_init()
-
# The support for running the examples and unit tests.
http_archive(
diff --git a/fuzzing/engines/BUILD b/fuzzing/engines/BUILD
index 82247fc..541b265 100644
--- a/fuzzing/engines/BUILD
+++ b/fuzzing/engines/BUILD
@@ -68,6 +68,16 @@
name = "jazzer",
display_name = "Jazzer",
launcher = "jazzer_launcher.sh",
- library = "@jazzer//agent:jazzer_api_compile_only",
+ library = ":jazzer_stub",
visibility = ["//visibility:public"],
)
+
+# This wrapper target is needed as Jazzer consists of two separate Java targets,
+# but java_fuzzing_engine's library attribute only accepts a single target.
+java_library(
+ name = "jazzer_stub",
+ exports = [
+ "@rules_fuzzing_jazzer//jar",
+ "@rules_fuzzing_jazzer_api//jar",
+ ],
+)
diff --git a/fuzzing/private/BUILD b/fuzzing/private/BUILD
index 3eb5186..2c41ca3 100644
--- a/fuzzing/private/BUILD
+++ b/fuzzing/private/BUILD
@@ -29,36 +29,28 @@
"util.bzl",
])
-# Config settings needed for prebuilt engines.
config_setting(
- name = "use_sanitizer_none",
+ name = "is_oss_fuzz",
flag_values = {
- "@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
+ "@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
},
+ visibility = ["//visibility:public"],
)
config_setting(
- name = "use_sanitizer_asan",
+ name = "use_asan",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "asan",
},
+ visibility = ["//visibility:public"],
)
config_setting(
- name = "use_sanitizer_ubsan",
+ name = "use_ubsan",
flag_values = {
"@rules_fuzzing//fuzzing:cc_engine_sanitizer": "ubsan",
},
-)
-
-config_setting(
- name = "use_oss_fuzz",
- flag_values = {
- "@rules_fuzzing//fuzzing:cc_engine": "@rules_fuzzing_oss_fuzz//:oss_fuzz_engine",
- # This is required to make the setting an unambiguous specialization of
- # the use_sanitizer_* settings.
- "@rules_fuzzing//fuzzing:cc_engine_sanitizer": "none",
- },
+ visibility = ["//visibility:public"],
)
exports_files([
diff --git a/fuzzing/private/fuzz_test.bzl b/fuzzing/private/fuzz_test.bzl
index 3a21942..b35024a 100644
--- a/fuzzing/private/fuzz_test.bzl
+++ b/fuzzing/private/fuzz_test.bzl
@@ -14,6 +14,7 @@
"""The implementation of the {cc, java}_fuzz_test rules."""
+load("@rules_fuzzing_oss_fuzz//:instrum.bzl", "native_library_sanitizer")
load("@rules_cc//cc:defs.bzl", "cc_binary")
# 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 @@
test_timeout = timeout,
)
+_ASAN_RUNTIME = Label("//fuzzing/private/runtime:asan")
+_UBSAN_RUNTIME = Label("//fuzzing/private/runtime:ubsan")
+_RUNTIME_BY_NAME = {
+ "asan": _ASAN_RUNTIME,
+ "ubsan": _UBSAN_RUNTIME,
+ "none": None,
+}
+
+# buildifier: disable=list-append
def java_fuzz_test(
name,
srcs = None,
@@ -264,6 +274,8 @@
# this target directly. Instead, the binary should be built through the
# instrumented configuration.
raw_target_name = name + "_target_"
+ metadata_binary_name = name + "_metadata_"
+ metadata_deploy_jar_name = metadata_binary_name + "_deploy.jar"
# Determine a value for target_class heuristically using the same rules as
# those used by Bazel internally for main_class.
@@ -277,62 +289,71 @@
name = name,
))
target_class_manifest_line = "Jazzer-Fuzz-Target-Class: %s" % target_class
- binary_kwargs.setdefault("deps", [])
- # Use += rather than append to allow users to pass in select() expressions for
+ native.java_binary(
+ name = metadata_binary_name,
+ deploy_manifest_lines = [target_class_manifest_line],
+ tags = ["manual"],
+ )
+
+ # use += rather than append to allow users to pass in select() expressions for
# deps, which only support concatenation with +.
- # Workaround for https://github.com/bazelbuild/bazel/issues/14157.
- # buildifier: disable=list-append
- binary_kwargs["deps"] += [engine]
- binary_kwargs.setdefault("deploy_manifest_lines", [])
+ # workaround for https://github.com/bazelbuild/bazel/issues/14157.
+ if srcs:
+ binary_kwargs.setdefault("deps", [])
+ binary_kwargs["deps"] += [engine, metadata_deploy_jar_name]
+ else:
+ binary_kwargs.setdefault("runtime_deps", [])
+ binary_kwargs["runtime_deps"] += [engine, metadata_deploy_jar_name]
- # buildifier: disable=list-append
- binary_kwargs["deploy_manifest_lines"] += [target_class_manifest_line]
+ binary_kwargs.setdefault("jvm_flags", [])
+ binary_kwargs["jvm_flags"] = [
+ # Ensures that full stack traces are emitted for findings even in highly
+ # optimized code.
+ "-XX:-OmitStackTraceInFastThrow",
+ # Optimized for throughput rather than latency.
+ "-XX:+UseParallelGC",
+ # Ignore CriticalJNINatives if not available (JDK 18+).
+ "-XX:+IgnoreUnrecognizedVMOptions",
+ # Improves performance of Jazzer's native compare instrumentation.
+ "-XX:+CriticalJNINatives",
+ ] + binary_kwargs["jvm_flags"]
# tags is not configurable and can thus use append.
binary_kwargs.setdefault("tags", []).append("manual")
native.java_binary(
name = raw_target_name,
srcs = srcs,
- create_executable = False,
+ main_class = "com.code_intelligence.jazzer.Jazzer",
**binary_kwargs
)
raw_binary_name = name + "_raw_"
jazzer_fuzz_binary(
name = raw_binary_name,
- agent = select({
- "@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_agent_deploy.jar",
- "//conditions:default": "@jazzer//agent:jazzer_agent_deploy.jar",
+ sanitizer = select({
+ "@rules_fuzzing//fuzzing/private:is_oss_fuzz": native_library_sanitizer,
+ "@rules_fuzzing//fuzzing/private:use_asan": "asan",
+ "@rules_fuzzing//fuzzing/private:use_ubsan": "ubsan",
+ "//conditions:default": "none",
}),
- # Since the choice of sanitizer is explicit for local fuzzing, we also
- # let it apply to projects with no native dependencies.
- driver_java_only = select({
- "@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
- }, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
- driver_with_native = select({
- "@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing_oss_fuzz//:jazzer_driver_with_sanitizer",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_none": "@jazzer//driver:jazzer_driver",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_asan": "@jazzer//driver:jazzer_driver_asan",
- "@rules_fuzzing//fuzzing/private:use_sanitizer_ubsan": "@jazzer//driver:jazzer_driver_ubsan",
- }, no_match_error = "Jazzer only supports the sanitizer settings: \"none\", \"asan\", \"ubsan\""),
sanitizer_options = select({
- "@rules_fuzzing//fuzzing/private:use_oss_fuzz": "@rules_fuzzing//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh",
- "//conditions:default": "@rules_fuzzing//fuzzing/private:local_jazzer_sanitizer_options.sh",
+ "@rules_fuzzing//fuzzing/private:is_oss_fuzz": Label("//fuzzing/private:oss_fuzz_jazzer_sanitizer_options.sh"),
+ "//conditions:default": Label("//fuzzing/private:local_jazzer_sanitizer_options.sh"),
}),
- tags = ["manual"],
+ sanitizer_runtime = select({
+ "@rules_fuzzing//fuzzing/private:is_oss_fuzz": _RUNTIME_BY_NAME[native_library_sanitizer],
+ "@rules_fuzzing//fuzzing/private:use_asan": _ASAN_RUNTIME,
+ "@rules_fuzzing//fuzzing/private:use_ubsan": _UBSAN_RUNTIME,
+ "//conditions:default": None,
+ }),
target = raw_target_name,
- target_deploy_jar = raw_target_name + "_deploy.jar",
+ tags = ["manual"],
)
fuzzing_decoration(
name = name,
raw_binary = raw_binary_name,
- # jazzer_fuzz_binary already instrumented the native dependencies.
- instrument_binary = False,
engine = engine,
corpus = corpus,
dicts = dicts,
diff --git a/fuzzing/private/java_utils.bzl b/fuzzing/private/java_utils.bzl
index 70c4e24..10b4bb7 100644
--- a/fuzzing/private/java_utils.bzl
+++ b/fuzzing/private/java_utils.bzl
@@ -81,7 +81,7 @@
return root_index
-def _jazzer_fuzz_binary_script(ctx, native_libs, driver):
+def _jazzer_fuzz_binary_script(ctx, target, sanitizer_flags):
script = ctx.actions.declare_file(ctx.label.name)
# The script is split into two parts: The first is emitted as-is, the second
@@ -93,16 +93,16 @@
# Bazel-provided code snippet that should be copy-pasted as is at use sites.
# Taken from @bazel_tools//tools/bash/runfiles.
-# --- begin runfiles.bash initialization v2 ---
-# Copy-pasted from the Bazel Bash runfiles library v2.
-set -uo pipefail; f=bazel_tools/tools/bash/runfiles/runfiles.bash
+# --- begin runfiles.bash initialization v3 ---
+# Copy-pasted from the Bazel Bash runfiles library v3.
+set -uo pipefail; set +e; f=bazel_tools/tools/bash/runfiles/runfiles.bash
source "${RUNFILES_DIR:-/dev/null}/$f" 2>/dev/null || \
-source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
-source "$0.runfiles/$f" 2>/dev/null || \
-source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
-source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
-{ echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
-# --- end runfiles.bash initialization v2 ---
+ source "$(grep -sm1 "^$f " "${RUNFILES_MANIFEST_FILE:-/dev/null}" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$0.runfiles/$f" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ source "$(grep -sm1 "^$f " "$0.exe.runfiles_manifest" | cut -f2- -d' ')" 2>/dev/null || \
+ { echo>&2 "ERROR: cannot find $f"; exit 1; }; f=; set -e
+# --- end runfiles.bash initialization v3 ---
# Export the env variables required for subprocesses to find their runfiles.
runfiles_export_envvars
@@ -116,127 +116,43 @@
script_format_part = """
source "$(rlocation {sanitizer_options})"
-exec "$(rlocation {driver})" \
- --agent_path="$(rlocation {agent})" \
- --cp="$(rlocation {deploy_jar})" \
- --jvm_args="-Djava.library.path={native_dirs}" \
- "$@"
+if [[ ! -z "{sanitizer_runtime}" ]]; then
+ export JAZZER_NATIVE_SANITIZERS_DIR=$(dirname "$(rlocation "{sanitizer_runtime}")")
+fi
+exec "$(rlocation {target})" {sanitizer_flags} "$@"
"""
- native_dirs = [
- "$(dirname \"$(rlocation %s)\")" % runfile_path(ctx, lib)
- for lib in native_libs
- ]
-
script_content = script_literal_part + script_format_part.format(
- agent = runfile_path(ctx, ctx.file.agent),
- deploy_jar = runfile_path(ctx, ctx.file.target_deploy_jar),
- driver = runfile_path(ctx, driver),
- # Jazzer requires the path separator to be escaped in --jvm_args.
- # See:
- # https://github.com/CodeIntelligenceTesting/jazzer#passing-jvm-arguments
- native_dirs = "\\:".join(native_dirs),
+ target = runfile_path(ctx, target),
+ sanitizer_flags = " ".join(sanitizer_flags),
sanitizer_options = runfile_path(ctx, ctx.file.sanitizer_options),
+ sanitizer_runtime = runfile_path(ctx, ctx.file.sanitizer_runtime) if ctx.file.sanitizer_runtime else "",
)
ctx.actions.write(script, script_content, is_executable = True)
return script
-def _is_required_runfile(runfile, runtime_classpath = []):
- # The jars in the runtime classpath are all merged into the deploy jar and
- # thus don't need to be included in the runfiles for the fuzzer.
- if runfile in runtime_classpath:
- return False
-
- # A java_binary target has a dependency on the local JDK. Since the Jazzer
- # driver launches its own JVM, these runfiles are not needed.
- if runfile.owner != None and runfile.owner.workspace_name == "local_jdk":
- return False
- return True
-
-def _filter_target_runfiles(ctx, target):
- compilation_info = target[JavaInfo].compilation_info
- runtime_classpath = compilation_info.runtime_classpath.to_list()
- all_runfiles = target[DefaultInfo].default_runfiles
- return ctx.runfiles([
- runfile
- for runfile in all_runfiles.files.to_list()
- if _is_required_runfile(runfile, runtime_classpath)
- ])
-
-def _is_potential_native_dependency(file):
- if file.extension not in ["dll", "dylib", "so"]:
- return False
- if not _is_required_runfile(file):
- return False
- return True
-
-def _native_library_files(ctx):
- target_info = ctx.attr.target[0][DefaultInfo]
- target_java_info = ctx.attr.target[0][JavaInfo]
-
- # Perform feature detection for
- # https://github.com/bazelbuild/bazel/commit/381a519dfc082d4c62096c4ce77ead1c2e0410d8.
- if hasattr(target_java_info, "transitive_native_libraries"):
- # The current version of Bazel contains the commit, which means that
- # the JavaInfo of the target includes information about all transitive
- # native library dependencies.
- native_libraries_list = target_java_info.transitive_native_libraries.to_list()
- return [
- lib.dynamic_library
- for lib in native_libraries_list
- if lib.dynamic_library != None
- ]
- else:
- # If precise information about transitive native libraries is not
- # available, fall back to an overapproximation that includes all
- # runfiles with file extensions indicating a shared library.
- runfiles_list = target_info.default_runfiles.files.to_list()
- return [
- runfile
- for runfile in runfiles_list
- if _is_potential_native_dependency(runfile)
- ]
-
def _jazzer_fuzz_binary_impl(ctx):
- native_libs = _native_library_files(ctx)
-
- # Use a driver with a linked in sanitizer if the fuzz test has native
- # dependencies.
- if native_libs:
- driver = ctx.executable.driver_with_native
- driver_info = ctx.attr.driver_with_native[DefaultInfo]
- else:
- driver = ctx.executable.driver_java_only
- driver_info = ctx.attr.driver_java_only[DefaultInfo]
-
- # The DefaultInfo's default_runfiles of an executable file target do not
- # contain the executable itself, which thus needs to be added explicitly.
- driver_runfiles = driver_info.default_runfiles
- driver_executable = driver_info.files_to_run.executable
- driver_runfiles = driver_runfiles.merge(ctx.runfiles([driver_executable]))
-
- runfiles = ctx.runfiles()
- runfiles = runfiles.merge(driver_runfiles)
+ sanitizer = ctx.attr.sanitizer
+ sanitizer_flags = []
+ if sanitizer in ["asan", "ubsan"]:
+ sanitizer_flags.append("--" + sanitizer)
+ if not sanitizer_flags and ctx.attr.target[0][JavaInfo].transitive_native_libraries:
+ sanitizer_flags.append("--native")
# Used by the wrapper script created in _jazzer_fuzz_binary_script.
- runfiles = runfiles.merge(ctx.attr._bash_runfiles_library[DefaultInfo].default_runfiles)
+ transitive_runfiles = [
+ ctx.attr.target[0][DefaultInfo].default_runfiles,
+ ctx.attr._bash_runfiles_library[DefaultInfo].default_runfiles,
+ ctx.runfiles(
+ [
+ ctx.file.sanitizer_options,
+ ] + ([ctx.file.sanitizer_runtime] if ctx.file.sanitizer_runtime else []),
+ ),
+ ]
+ runfiles = ctx.runfiles().merge_all(transitive_runfiles)
- # While the Jazzer agent is already included in the runfiles of
- # @jazzer//driver:jazzer_driver, it has to be added here explicitly for the
- # case where both are provided by OSS-Fuzz.
- runfiles = runfiles.merge(ctx.runfiles([ctx.file.agent]))
-
- # The Java fuzz target packaged as a jar including all Java dependencies.
- # This does not include e.g. data runfiles and shared libraries.
- runfiles = runfiles.merge(ctx.runfiles([ctx.file.target_deploy_jar]))
-
- # The full runfiles of the Java fuzz target, but with the files of the local
- # JDK and all jar files excluded.
- runfiles = runfiles.merge(_filter_target_runfiles(ctx, ctx.attr.target[0]))
-
- runfiles = runfiles.merge(ctx.runfiles([ctx.file.sanitizer_options]))
-
- script = _jazzer_fuzz_binary_script(ctx, native_libs, driver)
+ target = ctx.attr.target[0][DefaultInfo].files_to_run.executable
+ script = _jazzer_fuzz_binary_script(ctx, target, sanitizer_flags)
return [DefaultInfo(executable = script, runfiles = runfiles)]
jazzer_fuzz_binary = rule(
@@ -245,52 +161,31 @@
Rule that creates a binary that invokes Jazzer on the specified target.
""",
attrs = {
- "agent": attr.label(
- doc = "The Jazzer agent used to instrument the target.",
- allow_single_file = [".jar"],
- ),
- "_bash_runfiles_library": attr.label(
- default = "@bazel_tools//tools/bash/runfiles",
- ),
- "driver_java_only": attr.label(
- doc = "The Jazzer driver binary used to fuzz a Java-only target.",
- allow_single_file = True,
- executable = True,
- # Build in target configuration rather than host because the driver
- # uses transitions to set the correct C++ standard for its
- # dependencies.
- cfg = "target",
- ),
- "driver_with_native": attr.label(
- doc = "The Jazzer driver binary used to fuzz a Java target with " +
- "native dependencies.",
- allow_single_file = True,
- executable = True,
- # Build in target configuration rather than host because the driver
- # uses transitions to set the correct C++ standard for its
- # dependencies.
- cfg = "target",
+ "sanitizer": attr.string(
+ values = ["asan", "ubsan", "none"],
),
"sanitizer_options": attr.label(
doc = "A shell script that can export environment variables with " +
"sanitizer options.",
allow_single_file = [".sh"],
),
+ "sanitizer_runtime": attr.label(
+ doc = "The sanitizer runtime to preload.",
+ allow_single_file = [".dylib", ".so"],
+ ),
"target": attr.label(
doc = "The fuzz target.",
mandatory = True,
providers = [JavaInfo],
cfg = fuzzing_binary_transition,
),
- "target_deploy_jar": attr.label(
- doc = "The deploy jar of the fuzz target.",
- allow_single_file = [".jar"],
- mandatory = True,
- cfg = fuzzing_binary_transition,
- ),
+ "use_oss_fuzz": attr.bool(),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
+ "_bash_runfiles_library": attr.label(
+ default = "@bazel_tools//tools/bash/runfiles",
+ ),
},
executable = True,
)
diff --git a/fuzzing/private/oss_fuzz/BUILD.tpl b/fuzzing/private/oss_fuzz/BUILD.tpl
index aa41c48..2082067 100644
--- a/fuzzing/private/oss_fuzz/BUILD.tpl
+++ b/fuzzing/private/oss_fuzz/BUILD.tpl
@@ -13,6 +13,7 @@
# limitations under the License.
load("@rules_fuzzing//fuzzing:cc_defs.bzl", "cc_fuzzing_engine")
+load("@rules_fuzzing//fuzzing:java_defs.bzl", "java_fuzzing_engine")
load("@rules_cc//cc:defs.bzl", "cc_library")
cc_fuzzing_engine(
@@ -29,6 +30,18 @@
linkopts = [%{stub_linkopts}],
)
-exports_files([
- "instrum.bzl", %{exported_files}
-])
\ No newline at end of file
+java_fuzzing_engine(
+ name = "oss_fuzz_java_engine",
+ display_name = "OSS-Fuzz (Java)",
+ launcher = "oss_fuzz_launcher.sh",
+ library = ":oss_fuzz_java_stub",
+ visibility = ["//visibility:public"],
+)
+
+java_import(
+ name = "oss_fuzz_java_stub",
+ jars = [%{jazzer_jars}],
+)
+
+
+exports_files(["instrum.bzl"])
diff --git a/fuzzing/private/oss_fuzz/instrum.bzl.tpl b/fuzzing/private/oss_fuzz/instrum.bzl.tpl
index 04f1e54..14a34d4 100644
--- a/fuzzing/private/oss_fuzz/instrum.bzl.tpl
+++ b/fuzzing/private/oss_fuzz/instrum.bzl.tpl
@@ -20,3 +20,5 @@
conlyopts = [%{conlyopts}],
cxxopts = [%{cxxopts}],
)
+
+native_library_sanitizer = "%{sanitizer}"
diff --git a/fuzzing/private/oss_fuzz/package.bzl b/fuzzing/private/oss_fuzz/package.bzl
index e5e9dc4..e0ae8ed 100644
--- a/fuzzing/private/oss_fuzz/package.bzl
+++ b/fuzzing/private/oss_fuzz/package.bzl
@@ -34,8 +34,9 @@
# the runfiles here. This deviates from the usual Bazel runfiles layout,
# but is required since ClusterFuzz executes fuzz targets in
# subdirectories and would thus duplicate every C++ fuzz target.
+ # We also exclude the local JDK as OSS-Fuzz provides one.
for runfile in binary_runfiles
- if runfile != binary_info.binary_file
+ if runfile != binary_info.binary_file and not runfile_path(ctx, runfile).startswith("local_jdk/")
])
ctx.actions.write(runfiles_manifest, runfiles_manifest_content, False)
archive_inputs.append(runfiles_manifest)
diff --git a/fuzzing/private/oss_fuzz/repository.bzl b/fuzzing/private/oss_fuzz/repository.bzl
index 45212e5..0f81811 100644
--- a/fuzzing/private/oss_fuzz/repository.bzl
+++ b/fuzzing/private/oss_fuzz/repository.bzl
@@ -70,22 +70,13 @@
instrum_cxxopts = instrum_cxxopts,
)
-# The filenames under which the various Jazzer binaries are available in $OUT
-# and in @rules_fuzzing_oss_fuzz.
-_JAZZER_BINARIES = [
- "jazzer_agent_deploy.jar",
- "jazzer_driver",
- "jazzer_driver_with_sanitizer",
-]
+_JAZZER_JAR = "jazzer_agent_deploy.jar"
-def _export_jazzer(repository_ctx, out_path):
+def _link_jazzer_jars(repository_ctx, out_path):
if out_path == None:
return []
- exported_files = []
- for jazzer_binary in _JAZZER_BINARIES:
- repository_ctx.symlink(out_path + "/" + jazzer_binary, jazzer_binary)
- exported_files.append(jazzer_binary)
- return exported_files
+ repository_ctx.symlink(out_path + "/" + _JAZZER_JAR, _JAZZER_JAR)
+ return [_JAZZER_JAR]
def _oss_fuzz_repository(repository_ctx):
environ = repository_ctx.os.environ
@@ -102,7 +93,6 @@
cflags.split(" "),
cxxflags.split(" "),
)
- exported_files = _export_jazzer(repository_ctx, out_path)
repository_ctx.template(
"BUILD",
@@ -110,7 +100,7 @@
{
"%{stub_srcs}": _to_list_repr(build_params.stub_srcs),
"%{stub_linkopts}": _to_list_repr(build_params.stub_linkopts),
- "%{exported_files}": _to_list_repr(exported_files),
+ "%{jazzer_jars}": _to_list_repr(_link_jazzer_jars(repository_ctx, out_path)),
},
)
repository_ctx.template(
@@ -119,6 +109,10 @@
{
"%{conlyopts}": _to_list_repr(build_params.instrum_conlyopts),
"%{cxxopts}": _to_list_repr(build_params.instrum_cxxopts),
+ "%{sanitizer}": {
+ "address": "asan",
+ "undefined": "ubsan",
+ }.get(sanitizer, "none"),
},
)
repository_ctx.file(
diff --git a/fuzzing/private/runtime/BUILD b/fuzzing/private/runtime/BUILD
new file mode 100644
index 0000000..1e35809
--- /dev/null
+++ b/fuzzing/private/runtime/BUILD
@@ -0,0 +1,53 @@
+load(":clang_runtime_lib.bzl", "clang_runtime_lib")
+
+alias(
+ name = "asan",
+ actual = select({
+ "@platforms//os:linux": ":asan_linux",
+ "@platforms//os:macos": ":asan_macos",
+ }),
+ visibility = ["//visibility:public"],
+)
+
+alias(
+ name = "ubsan",
+ actual = select({
+ "@platforms//os:linux": ":ubsan_linux",
+ "@platforms//os:macos": ":ubsan_macos",
+ }),
+ visibility = ["//visibility:public"],
+)
+
+clang_runtime_lib(
+ name = "asan_linux",
+ basenames = [
+ # LLVM 15+
+ "libclang_rt.asan.so",
+ # LLVM 14 and earlier
+ "libclang_rt.asan-x86_64.so",
+ ],
+ tags = ["manual"],
+)
+
+clang_runtime_lib(
+ name = "asan_macos",
+ basenames = ["libclang_rt.asan_osx_dynamic.dylib"],
+ tags = ["manual"],
+)
+
+clang_runtime_lib(
+ name = "ubsan_linux",
+ basenames = [
+ # LLVM 15+
+ "libclang_rt.ubsan_standalone.so",
+ # LLVM 14 and earlier
+ "libclang_rt.ubsan_standalone-x86_64.so",
+ ],
+ tags = ["manual"],
+)
+
+clang_runtime_lib(
+ name = "ubsan_macos",
+ basenames = ["libclang_rt.ubsan_osx_dynamic.dylib"],
+ tags = ["manual"],
+)
diff --git a/fuzzing/private/runtime/clang_runtime_lib.bzl b/fuzzing/private/runtime/clang_runtime_lib.bzl
new file mode 100644
index 0000000..6098ff2
--- /dev/null
+++ b/fuzzing/private/runtime/clang_runtime_lib.bzl
@@ -0,0 +1,29 @@
+# Copyright 2023 Google LLC
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# https://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Macro that extracts clang runtime libraries from the current cc_toolchain."""
+
+def clang_runtime_lib(*, name, basenames, **kwargs):
+ """Provide the first available clang runtime library with any of the given basenames as output.
+
+ The basename of the output file is always the first of the given basenames.
+ """
+ native.genrule(
+ name = name,
+ outs = basenames[:1],
+ cmd = "\n".join(["""cp -f "$$($(CC) --print-file-name {})" $@ 2> /dev/null || true""".format(basename) for basename in basenames]),
+ toolchains = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
+ tools = ["@bazel_tools//tools/cpp:current_cc_toolchain"],
+ **kwargs
+ )
diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl
index b823967..f107b1b 100644
--- a/fuzzing/repositories.bzl
+++ b/fuzzing/repositories.bzl
@@ -14,19 +14,17 @@
"""Contains the external dependencies."""
-load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_jar")
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
load("//fuzzing/private/oss_fuzz:repository.bzl", "oss_fuzz_repository")
-def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = False):
+def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True):
"""Instantiates the dependencies of the fuzzing rules.
Args:
oss_fuzz: Include OSS-Fuzz dependencies.
honggfuzz: Include Honggfuzz dependencies.
- jazzer: Include Jazzer repository. Instantiating all Jazzer dependencies
- additionally requires invoking jazzer_dependencies() in
- @jazzer//:repositories.bzl and jazzer_init() in @jazzer//:init.bzl.
+ jazzer: Include Jazzer dependencies.
"""
maybe(
@@ -80,9 +78,15 @@
if jazzer:
maybe(
- http_archive,
- name = "jazzer",
- sha256 = "c55889c235501498ca7436f57974ea59f0dc43e9effd64e13ce0c535265b8224",
- strip_prefix = "jazzer-4434041f088365acf2a561e678bf9d61a7aa5dff",
- url = "https://github.com/CodeIntelligenceTesting/jazzer/archive/4434041f088365acf2a561e678bf9d61a7aa5dff.zip",
+ http_jar,
+ name = "rules_fuzzing_jazzer",
+ sha256 = "ccf5379c8c296bdcf0dda9b2253a7a34ce0726aa69c00a09bc66c38146167a30",
+ url = "https://repo1.maven.org/maven2/com/code-intelligence/jazzer/0.17.1/jazzer-0.17.1.jar",
+ )
+
+ maybe(
+ http_jar,
+ name = "rules_fuzzing_jazzer_api",
+ sha256 = "b73cbbbda3b9eba14b3060d706f173e59c3512fb84fd0a4f3b0906541232d6e4",
+ url = "https://repo1.maven.org/maven2/com/code-intelligence/jazzer-api/0.17.1/jazzer-api-0.17.1.jar",
)