Support for using honggfuzz with gcc (#288)
This allows running honggfuzz with a gcc toolchain which can be useful
for code bases that don't compile with clang or where no clang toolchain
is available.
Example usage:
```
bazel run //examples:re2_fuzz_test --config asan-honggfuzz
```
---------
Co-authored-by: Simon Resch <simon.resch@code-intelligence.de>
Co-authored-by: Markus Zoppelt <markus@zoppelt.net>
Co-authored-by: Markus Zoppelt <markus.zoppelt@code-intelligence.com>
diff --git a/.bazelrc b/.bazelrc
index f64a009..b666ec6 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -12,7 +12,7 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-# Force the use of Clang for all builds.
+# Set clang as the default compiler for most configurations.
build --repo_env=CC=clang
# Strict dependency check for C++ includes.
@@ -68,6 +68,12 @@
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan
+# Honggfuzz + ASAN (GCC)
+build:asan-honggfuzz-gcc --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
+build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
+build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan
+build:asan-honggfuzz-gcc --repo_env=CC=gcc
+
# Replay + ASAN
build:asan-replay --//fuzzing:cc_engine=//fuzzing/engines:replay
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none
diff --git a/README.md b/README.md
index 0aa2822..44f6fca 100644
--- a/README.md
+++ b/README.md
@@ -35,10 +35,10 @@
The fuzzing rules have been tested on Bazel 4.0.0 or later. Check your Bazel version by running `bazel --version`.
-C++ fuzzing requires a Clang compiler. The libFuzzer engine requires at least Clang 6.0. In addition, the Honggfuzz engine requires the `libunwind-dev` and `libblocksruntime-dev` packages:
+The libFuzzer engine requires at least Clang 6.0. Honggfuzz works with both clang and gcc (8 or later) and requires the `libunwind-dev` and `libblocksruntime-dev` packages:
```sh
-$ sudo apt-get install clang libunwind-dev libblocksruntime-dev
+$ sudo apt-get install libunwind-dev libblocksruntime-dev
```
Java fuzzing requires Clang and the LLD linker:
diff --git a/fuzzing/instrum_opts.bzl b/fuzzing/instrum_opts.bzl
index a6eadbe..19272e9 100644
--- a/fuzzing/instrum_opts.bzl
+++ b/fuzzing/instrum_opts.bzl
@@ -29,21 +29,35 @@
"oss_fuzz_opts",
)
-# Fuzz test binary instrumentation configurations.
+# Fuzz test binary instrumentation configurations by compiler type.
instrum_configs = {
- "none": instrum_opts.make(),
- "libfuzzer": instrum_defaults.libfuzzer,
- "jazzer": instrum_defaults.jazzer,
- "honggfuzz": instrum_defaults.honggfuzz,
- "oss-fuzz": oss_fuzz_opts,
+ "clang": {
+ "none": instrum_opts.make(),
+ "libfuzzer": instrum_defaults.libfuzzer,
+ "jazzer": instrum_defaults.jazzer,
+ "honggfuzz": instrum_defaults.honggfuzz_clang,
+ "oss-fuzz": oss_fuzz_opts,
+ },
+ "gcc": {
+ "none": instrum_opts.make(),
+ "honggfuzz": instrum_defaults.honggfuzz_gcc,
+ },
}
-# Sanitizer configurations.
+# Sanitizer configurations by compiler type.
sanitizer_configs = {
- "none": instrum_opts.make(),
- "asan": instrum_defaults.asan,
- "msan": instrum_defaults.msan,
- "msan-origin-tracking": instrum_defaults.msan_origin_tracking,
- "ubsan": instrum_defaults.ubsan,
- "asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan),
+ "clang": {
+ "none": instrum_opts.make(),
+ "asan": instrum_defaults.asan,
+ "msan": instrum_defaults.msan,
+ "msan-origin-tracking": instrum_defaults.msan_origin_tracking,
+ "ubsan": instrum_defaults.ubsan_clang,
+ "asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan_clang),
+ },
+ "gcc": {
+ "none": instrum_opts.make(),
+ "asan": instrum_defaults.asan,
+ "ubsan": instrum_defaults.ubsan_gcc,
+ "asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan_gcc),
+ },
}
diff --git a/fuzzing/private/binary.bzl b/fuzzing/private/binary.bzl
index 8ff9723..622788d 100644
--- a/fuzzing/private/binary.bzl
+++ b/fuzzing/private/binary.bzl
@@ -47,29 +47,30 @@
},
)
-def _fuzzing_binary_transition_impl(settings, _attr):
+def _fuzzing_binary_transition_impl(settings, attr):
opts = instrum_opts.make(
copts = settings["//command_line_option:copt"],
conlyopts = settings["//command_line_option:conlyopt"],
cxxopts = settings["//command_line_option:cxxopt"],
linkopts = settings["//command_line_option:linkopt"],
)
+ compiler_type = getattr(attr, "compiler", "clang")
is_fuzzing_build_mode = settings["@rules_fuzzing//fuzzing:cc_fuzzing_build_mode"]
if is_fuzzing_build_mode:
opts = instrum_opts.merge(opts, instrum_defaults.fuzzing_build)
instrum_config = settings["@rules_fuzzing//fuzzing:cc_engine_instrumentation"]
- if instrum_config in instrum_configs:
- opts = instrum_opts.merge(opts, instrum_configs[instrum_config])
+ if instrum_config in instrum_configs[compiler_type]:
+ opts = instrum_opts.merge(opts, instrum_configs[compiler_type][instrum_config])
else:
- fail("unsupported engine instrumentation '%s'" % instrum_config)
+ fail("unsupported engine instrumentation '%s' for compiler '%s'" % (instrum_config, compiler_type))
sanitizer_config = settings["@rules_fuzzing//fuzzing:cc_engine_sanitizer"]
- if sanitizer_config in sanitizer_configs:
- opts = instrum_opts.merge(opts, sanitizer_configs[sanitizer_config])
+ if sanitizer_config in sanitizer_configs[compiler_type]:
+ opts = instrum_opts.merge(opts, sanitizer_configs[compiler_type][sanitizer_config])
else:
- fail("unsupported sanitizer '%s'" % sanitizer_config)
+ fail("unsupported sanitizer '%s' for compiler '%s'" % (sanitizer_config, compiler_type))
return {
"//command_line_option:copt": opts.copts,
@@ -185,6 +186,11 @@
cfg = fuzzing_binary_transition,
mandatory = True,
),
+ "compiler": attr.string(
+ default = "clang",
+ values = ["clang", "gcc"],
+ doc = "The compiler used to build the fuzz test executable.",
+ ),
"_allowlist_function_transition": attr.label(
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
),
diff --git a/fuzzing/private/extensions.bzl b/fuzzing/private/extensions.bzl
index 3700810..a6b0b68 100644
--- a/fuzzing/private/extensions.bzl
+++ b/fuzzing/private/extensions.bzl
@@ -18,7 +18,7 @@
load("//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
def _non_module_dependencies(mctx):
- rules_fuzzing_dependencies()
+ rules_fuzzing_dependencies(bzlmod = True)
if bazel_features.external_deps.extension_metadata_has_reproducible:
return mctx.extension_metadata(reproducible = True)
diff --git a/fuzzing/private/fuzz_test.bzl b/fuzzing/private/fuzz_test.bzl
index a2e4cb5..60d2157 100644
--- a/fuzzing/private/fuzz_test.bzl
+++ b/fuzzing/private/fuzz_test.bzl
@@ -88,6 +88,10 @@
fuzzing_binary(
name = instrum_binary_name,
binary = raw_binary,
+ compiler = select({
+ str(Label("@rules_cc//cc/compiler:gcc")): "gcc",
+ "//conditions:default": "clang",
+ }),
engine = engine,
corpus = corpus_name,
dictionary = dict_name if dicts else None,
diff --git a/fuzzing/private/instrum_opts.bzl b/fuzzing/private/instrum_opts.bzl
index 60cea93..1c723bb 100644
--- a/fuzzing/private/instrum_opts.bzl
+++ b/fuzzing/private/instrum_opts.bzl
@@ -91,7 +91,7 @@
),
# Reflects the set of options at
# https://github.com/google/honggfuzz/blob/master/hfuzz_cc/hfuzz-cc.c
- honggfuzz = _make_opts(
+ honggfuzz_clang = _make_opts(
copts = [
"-mllvm",
"-inline-threshold=2000",
@@ -105,6 +105,16 @@
"-fno-sanitize=fuzzer",
],
),
+ honggfuzz_gcc = _make_opts(
+ copts = [
+ "-finline-limit=1000",
+ "-fsanitize-coverage=trace-pc,trace-cmp",
+ "-fno-builtin",
+ "-fno-omit-frame-pointer",
+ "-D__NO_STRING_INLINES",
+ ],
+ linkopts = [],
+ ),
asan = _make_opts(
copts = ["-fsanitize=address"],
linkopts = ["-fsanitize=address"],
@@ -120,7 +130,7 @@
],
linkopts = ["-fsanitize=memory"],
),
- ubsan = _make_opts(
+ ubsan_clang = _make_opts(
copts = [
"-fsanitize=undefined",
],
@@ -133,4 +143,12 @@
"-fsanitize-link-c++-runtime",
],
),
+ ubsan_gcc = _make_opts(
+ copts = [
+ "-fsanitize=undefined",
+ ],
+ linkopts = [
+ "-fsanitize=undefined",
+ ],
+ ),
)
diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl
index 2c5a367..388ded9 100644
--- a/fuzzing/repositories.bzl
+++ b/fuzzing/repositories.bzl
@@ -18,47 +18,49 @@
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 = True):
+def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True, bzlmod = False):
"""Instantiates the dependencies of the fuzzing rules.
Args:
oss_fuzz: Include OSS-Fuzz dependencies.
honggfuzz: Include Honggfuzz dependencies.
jazzer: Include Jazzer dependencies.
+ bzlmod: Whether to exclude dependencies that are already provided by bazel_deps.
"""
- maybe(
- http_archive,
- name = "platforms",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
- "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
- ],
- sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74",
- )
- maybe(
- http_archive,
- name = "rules_python",
- sha256 = "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8",
- strip_prefix = "rules_python-0.28.0",
- url = "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz",
- )
- maybe(
- http_archive,
- name = "bazel_skylib",
- sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
- urls = [
- "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
- "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
- ],
- )
- maybe(
- http_archive,
- name = "com_google_absl",
- urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip"],
- strip_prefix = "abseil-cpp-20240116.1",
- integrity = "sha256-7capMWOvWyoYbUaHF/b+I2U6XLMaHmky8KugWvfXYuk=",
- )
+ if not bzlmod:
+ maybe(
+ http_archive,
+ name = "platforms",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
+ "https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
+ ],
+ sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74",
+ )
+ maybe(
+ http_archive,
+ name = "rules_python",
+ sha256 = "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8",
+ strip_prefix = "rules_python-0.28.0",
+ url = "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz",
+ )
+ maybe(
+ http_archive,
+ name = "bazel_skylib",
+ sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
+ urls = [
+ "https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
+ "https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
+ ],
+ )
+ maybe(
+ http_archive,
+ name = "com_google_absl",
+ urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip"],
+ strip_prefix = "abseil-cpp-20240116.1",
+ integrity = "sha256-7capMWOvWyoYbUaHF/b+I2U6XLMaHmky8KugWvfXYuk=",
+ )
if oss_fuzz:
maybe(
@@ -71,9 +73,9 @@
http_archive,
name = "honggfuzz",
build_file = "@rules_fuzzing//:honggfuzz.BUILD",
- sha256 = "6b18ba13bc1f36b7b950c72d80f19ea67fbadc0ac0bb297ec89ad91f2eaa423e",
- url = "https://github.com/google/honggfuzz/archive/2.5.zip",
- strip_prefix = "honggfuzz-2.5",
+ integrity = "sha256-d+DpDrzBMqmSNCuz0+/Vi3jTUiIFNnulWGAeBJaaHJM=",
+ url = "https://github.com/google/honggfuzz/archive/4cfa62f4fdb56e3027c1cb3aecf04812e786f0fd.zip",
+ strip_prefix = "honggfuzz-4cfa62f4fdb56e3027c1cb3aecf04812e786f0fd",
)
if jazzer:
diff --git a/honggfuzz.BUILD b/honggfuzz.BUILD
index 583e3f5..1b70a08 100644
--- a/honggfuzz.BUILD
+++ b/honggfuzz.BUILD
@@ -37,20 +37,31 @@
"-Wall",
"-Wextra",
"-Werror",
- "-Wno-override-init",
- "-Wno-initializer-overrides",
- "-Wno-gnu-empty-initializer",
- "-Wno-format-pedantic",
- "-Wno-gnu-statement-expression",
- "-mllvm",
- "-inline-threshold=2000",
- "-fblocks",
-
- # Do not instrument Honggfuzz itself, in order to avoid recursive
- # instrumentation calls that would crash the fuzz test binary.
- "-fsanitize-coverage=0",
- "-fno-sanitize=all",
-]
+] + select({
+ "@rules_cc//cc/compiler:gcc": [
+ "-Wno-override-init",
+ "-Wno-format-truncation",
+ # Do not instrument Honggfuzz itself, in order to avoid recursive
+ # instrumentation calls that would crash the fuzz test binary.
+ "-fno-sanitize-coverage=trace-pc,trace-cmp",
+ "-fno-sanitize=all",
+ ],
+ # Default to clang compiler flags
+ "//conditions:default": [
+ "-mllvm",
+ "-inline-threshold=2000",
+ "-fblocks",
+ "-Wno-override-init",
+ "-Wno-initializer-overrides",
+ "-Wno-gnu-empty-initializer",
+ "-Wno-format-pedantic",
+ "-Wno-gnu-statement-expression",
+ # Do not instrument Honggfuzz itself, in order to avoid recursive
+ # instrumentation calls that would crash the fuzz test binary.
+ "-fsanitize-coverage=0",
+ "-fno-sanitize=all",
+ ],
+})
LIBRARY_COPTS = [
"-fno-stack-protector",
@@ -116,6 +127,10 @@
"-Wl,--wrap=Curl_safe_strcasecompare",
"-Wl,--wrap=Curl_strncasecompare",
"-Wl,--wrap=curl_strnequal",
+ # SQLite3
+ "-Wl,--wrap=sqlite3_stricmp",
+ "-Wl,--wrap=sqlite3_strnicmp",
+ "-Wl,--wrap=sqlite3StrICmp",
],
})
@@ -147,6 +162,10 @@
deps = [
":honggfuzz_common",
],
+ target_compatible_with = select({
+ "@platforms//os:linux": [],
+ "//conditions:default": ["@platforms//:incompatible"],
+ }),
alwayslink = 1,
)