Skip to content

Commit e7abea6

Browse files
fmeumsimonreschMarkusZoppelt
authored
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>
1 parent 6e294e4 commit e7abea6

9 files changed

Lines changed: 145 additions & 76 deletions

File tree

.bazelrc

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
# Force the use of Clang for all builds.
15+
# Set clang as the default compiler for most configurations.
1616
build --repo_env=CC=clang
1717

1818
# Strict dependency check for C++ includes.
@@ -68,6 +68,12 @@ build:ubsan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
6868
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
6969
build:ubsan-honggfuzz --@rules_fuzzing//fuzzing:cc_engine_sanitizer=ubsan
7070

71+
# Honggfuzz + ASAN (GCC)
72+
build:asan-honggfuzz-gcc --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
73+
build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:cc_engine_instrumentation=honggfuzz
74+
build:asan-honggfuzz-gcc --@rules_fuzzing//fuzzing:cc_engine_sanitizer=asan
75+
build:asan-honggfuzz-gcc --repo_env=CC=gcc
76+
7177
# Replay + ASAN
7278
build:asan-replay --//fuzzing:cc_engine=//fuzzing/engines:replay
7379
build:asan-replay --@rules_fuzzing//fuzzing:cc_engine_instrumentation=none

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ This section will walk you through the steps to set up fuzzing in your Bazel pro
3535

3636
The fuzzing rules have been tested on Bazel 4.0.0 or later. Check your Bazel version by running `bazel --version`.
3737

38-
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:
38+
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:
3939

4040
```sh
41-
$ sudo apt-get install clang libunwind-dev libblocksruntime-dev
41+
$ sudo apt-get install libunwind-dev libblocksruntime-dev
4242
```
4343

4444
Java fuzzing requires Clang and the LLD linker:

fuzzing/instrum_opts.bzl

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -29,21 +29,35 @@ load(
2929
"oss_fuzz_opts",
3030
)
3131

32-
# Fuzz test binary instrumentation configurations.
32+
# Fuzz test binary instrumentation configurations by compiler type.
3333
instrum_configs = {
34-
"none": instrum_opts.make(),
35-
"libfuzzer": instrum_defaults.libfuzzer,
36-
"jazzer": instrum_defaults.jazzer,
37-
"honggfuzz": instrum_defaults.honggfuzz,
38-
"oss-fuzz": oss_fuzz_opts,
34+
"clang": {
35+
"none": instrum_opts.make(),
36+
"libfuzzer": instrum_defaults.libfuzzer,
37+
"jazzer": instrum_defaults.jazzer,
38+
"honggfuzz": instrum_defaults.honggfuzz_clang,
39+
"oss-fuzz": oss_fuzz_opts,
40+
},
41+
"gcc": {
42+
"none": instrum_opts.make(),
43+
"honggfuzz": instrum_defaults.honggfuzz_gcc,
44+
},
3945
}
4046

41-
# Sanitizer configurations.
47+
# Sanitizer configurations by compiler type.
4248
sanitizer_configs = {
43-
"none": instrum_opts.make(),
44-
"asan": instrum_defaults.asan,
45-
"msan": instrum_defaults.msan,
46-
"msan-origin-tracking": instrum_defaults.msan_origin_tracking,
47-
"ubsan": instrum_defaults.ubsan,
48-
"asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan),
49+
"clang": {
50+
"none": instrum_opts.make(),
51+
"asan": instrum_defaults.asan,
52+
"msan": instrum_defaults.msan,
53+
"msan-origin-tracking": instrum_defaults.msan_origin_tracking,
54+
"ubsan": instrum_defaults.ubsan_clang,
55+
"asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan_clang),
56+
},
57+
"gcc": {
58+
"none": instrum_opts.make(),
59+
"asan": instrum_defaults.asan,
60+
"ubsan": instrum_defaults.ubsan_gcc,
61+
"asan-ubsan": instrum_opts.merge(instrum_defaults.asan, instrum_defaults.ubsan_gcc),
62+
},
4963
}

fuzzing/private/binary.bzl

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -47,29 +47,30 @@ Provider for storing information about a fuzz test binary.
4747
},
4848
)
4949

50-
def _fuzzing_binary_transition_impl(settings, _attr):
50+
def _fuzzing_binary_transition_impl(settings, attr):
5151
opts = instrum_opts.make(
5252
copts = settings["//command_line_option:copt"],
5353
conlyopts = settings["//command_line_option:conlyopt"],
5454
cxxopts = settings["//command_line_option:cxxopt"],
5555
linkopts = settings["//command_line_option:linkopt"],
5656
)
57+
compiler_type = getattr(attr, "compiler", "clang")
5758

5859
is_fuzzing_build_mode = settings["@rules_fuzzing//fuzzing:cc_fuzzing_build_mode"]
5960
if is_fuzzing_build_mode:
6061
opts = instrum_opts.merge(opts, instrum_defaults.fuzzing_build)
6162

6263
instrum_config = settings["@rules_fuzzing//fuzzing:cc_engine_instrumentation"]
63-
if instrum_config in instrum_configs:
64-
opts = instrum_opts.merge(opts, instrum_configs[instrum_config])
64+
if instrum_config in instrum_configs[compiler_type]:
65+
opts = instrum_opts.merge(opts, instrum_configs[compiler_type][instrum_config])
6566
else:
66-
fail("unsupported engine instrumentation '%s'" % instrum_config)
67+
fail("unsupported engine instrumentation '%s' for compiler '%s'" % (instrum_config, compiler_type))
6768

6869
sanitizer_config = settings["@rules_fuzzing//fuzzing:cc_engine_sanitizer"]
69-
if sanitizer_config in sanitizer_configs:
70-
opts = instrum_opts.merge(opts, sanitizer_configs[sanitizer_config])
70+
if sanitizer_config in sanitizer_configs[compiler_type]:
71+
opts = instrum_opts.merge(opts, sanitizer_configs[compiler_type][sanitizer_config])
7172
else:
72-
fail("unsupported sanitizer '%s'" % sanitizer_config)
73+
fail("unsupported sanitizer '%s' for compiler '%s'" % (sanitizer_config, compiler_type))
7374

7475
return {
7576
"//command_line_option:copt": opts.copts,
@@ -185,6 +186,11 @@ The instrumentation is controlled by the following flags:
185186
cfg = fuzzing_binary_transition,
186187
mandatory = True,
187188
),
189+
"compiler": attr.string(
190+
default = "clang",
191+
values = ["clang", "gcc"],
192+
doc = "The compiler used to build the fuzz test executable.",
193+
),
188194
"_allowlist_function_transition": attr.label(
189195
default = "@bazel_tools//tools/allowlists/function_transition_allowlist",
190196
),

fuzzing/private/extensions.bzl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ load("@bazel_features//:features.bzl", "bazel_features")
1818
load("//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
1919

2020
def _non_module_dependencies(mctx):
21-
rules_fuzzing_dependencies()
21+
rules_fuzzing_dependencies(bzlmod = True)
2222

2323
if bazel_features.external_deps.extension_metadata_has_reproducible:
2424
return mctx.extension_metadata(reproducible = True)

fuzzing/private/fuzz_test.bzl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -88,6 +88,10 @@ def fuzzing_decoration(
8888
fuzzing_binary(
8989
name = instrum_binary_name,
9090
binary = raw_binary,
91+
compiler = select({
92+
str(Label("@rules_cc//cc/compiler:gcc")): "gcc",
93+
"//conditions:default": "clang",
94+
}),
9195
engine = engine,
9296
corpus = corpus_name,
9397
dictionary = dict_name if dicts else None,

fuzzing/private/instrum_opts.bzl

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,7 @@ instrum_defaults = struct(
9191
),
9292
# Reflects the set of options at
9393
# https://github.com/google/honggfuzz/blob/master/hfuzz_cc/hfuzz-cc.c
94-
honggfuzz = _make_opts(
94+
honggfuzz_clang = _make_opts(
9595
copts = [
9696
"-mllvm",
9797
"-inline-threshold=2000",
@@ -105,6 +105,16 @@ instrum_defaults = struct(
105105
"-fno-sanitize=fuzzer",
106106
],
107107
),
108+
honggfuzz_gcc = _make_opts(
109+
copts = [
110+
"-finline-limit=1000",
111+
"-fsanitize-coverage=trace-pc,trace-cmp",
112+
"-fno-builtin",
113+
"-fno-omit-frame-pointer",
114+
"-D__NO_STRING_INLINES",
115+
],
116+
linkopts = [],
117+
),
108118
asan = _make_opts(
109119
copts = ["-fsanitize=address"],
110120
linkopts = ["-fsanitize=address"],
@@ -120,7 +130,7 @@ instrum_defaults = struct(
120130
],
121131
linkopts = ["-fsanitize=memory"],
122132
),
123-
ubsan = _make_opts(
133+
ubsan_clang = _make_opts(
124134
copts = [
125135
"-fsanitize=undefined",
126136
],
@@ -133,4 +143,12 @@ instrum_defaults = struct(
133143
"-fsanitize-link-c++-runtime",
134144
],
135145
),
146+
ubsan_gcc = _make_opts(
147+
copts = [
148+
"-fsanitize=undefined",
149+
],
150+
linkopts = [
151+
"-fsanitize=undefined",
152+
],
153+
),
136154
)

fuzzing/repositories.bzl

Lines changed: 38 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,47 +18,49 @@ load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive", "http_jar")
1818
load("@bazel_tools//tools/build_defs/repo:utils.bzl", "maybe")
1919
load("//fuzzing/private/oss_fuzz:repository.bzl", "oss_fuzz_repository")
2020

21-
def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True):
21+
def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True, bzlmod = False):
2222
"""Instantiates the dependencies of the fuzzing rules.
2323
2424
Args:
2525
oss_fuzz: Include OSS-Fuzz dependencies.
2626
honggfuzz: Include Honggfuzz dependencies.
2727
jazzer: Include Jazzer dependencies.
28+
bzlmod: Whether to exclude dependencies that are already provided by bazel_deps.
2829
"""
2930

30-
maybe(
31-
http_archive,
32-
name = "platforms",
33-
urls = [
34-
"https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
35-
"https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
36-
],
37-
sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74",
38-
)
39-
maybe(
40-
http_archive,
41-
name = "rules_python",
42-
sha256 = "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8",
43-
strip_prefix = "rules_python-0.28.0",
44-
url = "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz",
45-
)
46-
maybe(
47-
http_archive,
48-
name = "bazel_skylib",
49-
sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
50-
urls = [
51-
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
52-
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
53-
],
54-
)
55-
maybe(
56-
http_archive,
57-
name = "com_google_absl",
58-
urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip"],
59-
strip_prefix = "abseil-cpp-20240116.1",
60-
integrity = "sha256-7capMWOvWyoYbUaHF/b+I2U6XLMaHmky8KugWvfXYuk=",
61-
)
31+
if not bzlmod:
32+
maybe(
33+
http_archive,
34+
name = "platforms",
35+
urls = [
36+
"https://mirror.bazel.build/github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
37+
"https://github.com/bazelbuild/platforms/releases/download/0.0.8/platforms-0.0.8.tar.gz",
38+
],
39+
sha256 = "8150406605389ececb6da07cbcb509d5637a3ab9a24bc69b1101531367d89d74",
40+
)
41+
maybe(
42+
http_archive,
43+
name = "rules_python",
44+
sha256 = "d70cd72a7a4880f0000a6346253414825c19cdd40a28289bdf67b8e6480edff8",
45+
strip_prefix = "rules_python-0.28.0",
46+
url = "https://github.com/bazelbuild/rules_python/releases/download/0.28.0/rules_python-0.28.0.tar.gz",
47+
)
48+
maybe(
49+
http_archive,
50+
name = "bazel_skylib",
51+
sha256 = "cd55a062e763b9349921f0f5db8c3933288dc8ba4f76dd9416aac68acee3cb94",
52+
urls = [
53+
"https://mirror.bazel.build/github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
54+
"https://github.com/bazelbuild/bazel-skylib/releases/download/1.5.0/bazel-skylib-1.5.0.tar.gz",
55+
],
56+
)
57+
maybe(
58+
http_archive,
59+
name = "com_google_absl",
60+
urls = ["https://github.com/abseil/abseil-cpp/archive/refs/tags/20240116.1.zip"],
61+
strip_prefix = "abseil-cpp-20240116.1",
62+
integrity = "sha256-7capMWOvWyoYbUaHF/b+I2U6XLMaHmky8KugWvfXYuk=",
63+
)
6264

6365
if oss_fuzz:
6466
maybe(
@@ -71,9 +73,9 @@ def rules_fuzzing_dependencies(oss_fuzz = True, honggfuzz = True, jazzer = True)
7173
http_archive,
7274
name = "honggfuzz",
7375
build_file = "@rules_fuzzing//:honggfuzz.BUILD",
74-
sha256 = "6b18ba13bc1f36b7b950c72d80f19ea67fbadc0ac0bb297ec89ad91f2eaa423e",
75-
url = "https://github.com/google/honggfuzz/archive/2.5.zip",
76-
strip_prefix = "honggfuzz-2.5",
76+
integrity = "sha256-d+DpDrzBMqmSNCuz0+/Vi3jTUiIFNnulWGAeBJaaHJM=",
77+
url = "https://github.com/google/honggfuzz/archive/4cfa62f4fdb56e3027c1cb3aecf04812e786f0fd.zip",
78+
strip_prefix = "honggfuzz-4cfa62f4fdb56e3027c1cb3aecf04812e786f0fd",
7779
)
7880

7981
if jazzer:

honggfuzz.BUILD

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -37,20 +37,31 @@ COMMON_COPTS = [
3737
"-Wall",
3838
"-Wextra",
3939
"-Werror",
40-
"-Wno-override-init",
41-
"-Wno-initializer-overrides",
42-
"-Wno-gnu-empty-initializer",
43-
"-Wno-format-pedantic",
44-
"-Wno-gnu-statement-expression",
45-
"-mllvm",
46-
"-inline-threshold=2000",
47-
"-fblocks",
48-
49-
# Do not instrument Honggfuzz itself, in order to avoid recursive
50-
# instrumentation calls that would crash the fuzz test binary.
51-
"-fsanitize-coverage=0",
52-
"-fno-sanitize=all",
53-
]
40+
] + select({
41+
"@rules_cc//cc/compiler:gcc": [
42+
"-Wno-override-init",
43+
"-Wno-format-truncation",
44+
# Do not instrument Honggfuzz itself, in order to avoid recursive
45+
# instrumentation calls that would crash the fuzz test binary.
46+
"-fno-sanitize-coverage=trace-pc,trace-cmp",
47+
"-fno-sanitize=all",
48+
],
49+
# Default to clang compiler flags
50+
"//conditions:default": [
51+
"-mllvm",
52+
"-inline-threshold=2000",
53+
"-fblocks",
54+
"-Wno-override-init",
55+
"-Wno-initializer-overrides",
56+
"-Wno-gnu-empty-initializer",
57+
"-Wno-format-pedantic",
58+
"-Wno-gnu-statement-expression",
59+
# Do not instrument Honggfuzz itself, in order to avoid recursive
60+
# instrumentation calls that would crash the fuzz test binary.
61+
"-fsanitize-coverage=0",
62+
"-fno-sanitize=all",
63+
],
64+
})
5465

5566
LIBRARY_COPTS = [
5667
"-fno-stack-protector",
@@ -116,6 +127,10 @@ SYMBOL_WRAP_LINKOPTS = select({
116127
"-Wl,--wrap=Curl_safe_strcasecompare",
117128
"-Wl,--wrap=Curl_strncasecompare",
118129
"-Wl,--wrap=curl_strnequal",
130+
# SQLite3
131+
"-Wl,--wrap=sqlite3_stricmp",
132+
"-Wl,--wrap=sqlite3_strnicmp",
133+
"-Wl,--wrap=sqlite3StrICmp",
119134
],
120135
})
121136

@@ -147,6 +162,10 @@ cc_library(
147162
deps = [
148163
":honggfuzz_common",
149164
],
165+
target_compatible_with = select({
166+
"@platforms//os:linux": [],
167+
"//conditions:default": ["@platforms//:incompatible"],
168+
}),
150169
alwayslink = 1,
151170
)
152171

0 commit comments

Comments
 (0)