From 68afda05182e1611672dade5e95af0aaa4662536 Mon Sep 17 00:00:00 2001 From: Simon Resch Date: Fri, 28 Mar 2025 14:00:24 +0100 Subject: [PATCH 1/4] Update honggfuzz dependency Using the latest mast commit since releases are very infrequent. --- fuzzing/repositories.bzl | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl index 2c5a367..7d5159f 100644 --- a/fuzzing/repositories.bzl +++ b/fuzzing/repositories.bzl @@ -71,9 +71,9 @@ def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True) 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: From 6c1572a1c18ae5b49ba8906cda3895cc6c4e8b3b Mon Sep 17 00:00:00 2001 From: Markus Zoppelt Date: Thu, 27 Mar 2025 15:09:09 +0100 Subject: [PATCH 2/4] Update wrapped function calls from hfuzz-cc.c Co-authored-by: Simon Resch --- honggfuzz.BUILD | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/honggfuzz.BUILD b/honggfuzz.BUILD index 583e3f5..c7de1f3 100644 --- a/honggfuzz.BUILD +++ b/honggfuzz.BUILD @@ -116,6 +116,10 @@ SYMBOL_WRAP_LINKOPTS = select({ "-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", ], }) From 7d9d04ffe52ee90acf968bd6fdc70446ac1fdd8a Mon Sep 17 00:00:00 2001 From: Simon Resch Date: Fri, 28 Mar 2025 14:06:06 +0100 Subject: [PATCH 3/4] Add support for honggfuzz in gcc mode Adds the flag --@rules_fuzzing//fuzzing:compiler_type with possible configurations "cmake" and "gcc". 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. Co-authored-by: Markus Zoppelt --- .bazelrc | 9 ++++++- README.md | 4 ++-- fuzzing/BUILD | 16 +++++++++++++ fuzzing/instrum_opts.bzl | 40 +++++++++++++++++++++----------- fuzzing/private/binary.bzl | 14 ++++++----- fuzzing/private/instrum_opts.bzl | 22 ++++++++++++++++-- honggfuzz.BUILD | 39 ++++++++++++++++++++----------- 7 files changed, 106 insertions(+), 38 deletions(-) diff --git a/.bazelrc b/.bazelrc index f64a009..1d71fcc 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,13 @@ build:ubsan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz 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 +build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:compiler_type=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 @@ This section will walk you through the steps to set up fuzzing in your Bazel pro 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/BUILD b/fuzzing/BUILD index fbf654a..67d76c8 100644 --- a/fuzzing/BUILD +++ b/fuzzing/BUILD @@ -73,6 +73,22 @@ bool_flag( visibility = ["//visibility:public"], ) +string_flag( + name = "compiler_type", + build_setting_default = "clang", + values = [ + "clang", + "gcc", + ], + visibility = ["//visibility:public"], +) + +config_setting( + name = "is_gcc", + flag_values = {":compiler_type": "gcc"}, + visibility = ["//visibility:public"], +) + exports_files([ "cc_defs.bzl", "java_defs.bzl", 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 @@ load( "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..2694bb1 100644 --- a/fuzzing/private/binary.bzl +++ b/fuzzing/private/binary.bzl @@ -54,22 +54,23 @@ def _fuzzing_binary_transition_impl(settings, _attr): cxxopts = settings["//command_line_option:cxxopt"], linkopts = settings["//command_line_option:linkopt"], ) + compiler_type = settings["@rules_fuzzing//fuzzing:compiler_type"] 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, @@ -87,6 +88,7 @@ fuzzing_binary_transition = transition( "@rules_fuzzing//fuzzing:cc_engine_instrumentation", "@rules_fuzzing//fuzzing:cc_engine_sanitizer", "@rules_fuzzing//fuzzing:cc_fuzzing_build_mode", + "@rules_fuzzing//fuzzing:compiler_type", "//command_line_option:copt", "//command_line_option:conlyopt", "//command_line_option:cxxopt", 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 @@ instrum_defaults = struct( ), # 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 @@ instrum_defaults = struct( "-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 @@ instrum_defaults = struct( ], linkopts = ["-fsanitize=memory"], ), - ubsan = _make_opts( + ubsan_clang = _make_opts( copts = [ "-fsanitize=undefined", ], @@ -133,4 +143,12 @@ instrum_defaults = struct( "-fsanitize-link-c++-runtime", ], ), + ubsan_gcc = _make_opts( + copts = [ + "-fsanitize=undefined", + ], + linkopts = [ + "-fsanitize=undefined", + ], + ), ) diff --git a/honggfuzz.BUILD b/honggfuzz.BUILD index c7de1f3..de5a793 100644 --- a/honggfuzz.BUILD +++ b/honggfuzz.BUILD @@ -37,20 +37,31 @@ COMMON_COPTS = [ "-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_fuzzing//fuzzing:is_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", From 9a102adc4542d585ae6761f2d93056b1e575106d Mon Sep 17 00:00:00 2001 From: Fabian Meumertzheim Date: Wed, 18 Mar 2026 12:55:39 +0100 Subject: [PATCH 4/4] Use `@rules_cc//cc/compiler` instead --- .bazelrc | 1 - fuzzing/BUILD | 16 -------- fuzzing/private/binary.bzl | 10 +++-- fuzzing/private/extensions.bzl | 2 +- fuzzing/private/fuzz_test.bzl | 4 ++ fuzzing/repositories.bzl | 68 +++++++++++++++++----------------- honggfuzz.BUILD | 6 ++- 7 files changed, 52 insertions(+), 55 deletions(-) diff --git a/.bazelrc b/.bazelrc index 1d71fcc..b666ec6 100644 --- a/.bazelrc +++ b/.bazelrc @@ -73,7 +73,6 @@ 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 -build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:compiler_type=gcc # Replay + ASAN build:asan-replay --//fuzzing:cc_engine=//fuzzing/engines:replay diff --git a/fuzzing/BUILD b/fuzzing/BUILD index 67d76c8..fbf654a 100644 --- a/fuzzing/BUILD +++ b/fuzzing/BUILD @@ -73,22 +73,6 @@ bool_flag( visibility = ["//visibility:public"], ) -string_flag( - name = "compiler_type", - build_setting_default = "clang", - values = [ - "clang", - "gcc", - ], - visibility = ["//visibility:public"], -) - -config_setting( - name = "is_gcc", - flag_values = {":compiler_type": "gcc"}, - visibility = ["//visibility:public"], -) - exports_files([ "cc_defs.bzl", "java_defs.bzl", diff --git a/fuzzing/private/binary.bzl b/fuzzing/private/binary.bzl index 2694bb1..622788d 100644 --- a/fuzzing/private/binary.bzl +++ b/fuzzing/private/binary.bzl @@ -47,14 +47,14 @@ Provider for storing information about a fuzz test binary. }, ) -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 = settings["@rules_fuzzing//fuzzing:compiler_type"] + compiler_type = getattr(attr, "compiler", "clang") is_fuzzing_build_mode = settings["@rules_fuzzing//fuzzing:cc_fuzzing_build_mode"] if is_fuzzing_build_mode: @@ -88,7 +88,6 @@ fuzzing_binary_transition = transition( "@rules_fuzzing//fuzzing:cc_engine_instrumentation", "@rules_fuzzing//fuzzing:cc_engine_sanitizer", "@rules_fuzzing//fuzzing:cc_fuzzing_build_mode", - "@rules_fuzzing//fuzzing:compiler_type", "//command_line_option:copt", "//command_line_option:conlyopt", "//command_line_option:cxxopt", @@ -187,6 +186,11 @@ The instrumentation is controlled by the following flags: 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("@bazel_features//:features.bzl", "bazel_features") 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 @@ def fuzzing_decoration( 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/repositories.bzl b/fuzzing/repositories.bzl index 7d5159f..388ded9 100644 --- a/fuzzing/repositories.bzl +++ b/fuzzing/repositories.bzl @@ -18,47 +18,49 @@ 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 = 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( diff --git a/honggfuzz.BUILD b/honggfuzz.BUILD index de5a793..1b70a08 100644 --- a/honggfuzz.BUILD +++ b/honggfuzz.BUILD @@ -38,7 +38,7 @@ COMMON_COPTS = [ "-Wextra", "-Werror", ] + select({ - "@rules_fuzzing//fuzzing:is_gcc": [ + "@rules_cc//cc/compiler:gcc": [ "-Wno-override-init", "-Wno-format-truncation", # Do not instrument Honggfuzz itself, in order to avoid recursive @@ -162,6 +162,10 @@ cc_library( deps = [ ":honggfuzz_common", ], + target_compatible_with = select({ + "@platforms//os:linux": [], + "//conditions:default": ["@platforms//:incompatible"], + }), alwayslink = 1, )