Add Honggfuzz engine support through the --config=asan-honggfuzz build config. (#75)

* Add Honggfuzz support.

This includes importing and building Honggfuzz with Bazel, as well as
defining a cc_fuzzing_engine specification for it.

* Starlark linter fixes.

* Further tweaks to the HF build options.

This brings the build options in closer aligment to the
HF Makefile and wrapper tool.

* Split the buffer overflow example in two cases.

First case causes overflow on input buffer.
Second case overflows on local buffer copy.

* Update README with Honggfuzz config.

* Add timeout support in Honggfuzz.

* Addressed reviewer comments.
diff --git a/.bazelrc b/.bazelrc
index ee2b0c8..87914b6 100644
--- a/.bazelrc
+++ b/.bazelrc
@@ -29,6 +29,21 @@
 build:asan-libfuzzer --copt=-fsanitize=fuzzer,address
 build:asan-libfuzzer --//fuzzing:cc_engine=//fuzzing/engines:libfuzzer
 
+# Flags for Clang with ASAN and Honggfuzz.
+# Reflects the set of options at
+# https://github.com/google/honggfuzz/blob/master/hfuzz_cc/hfuzz-cc.c
+build:asan-honggfuzz --config=_fuzzer_common
+build:asan-honggfuzz --dynamic_mode=off
+build:asan-honggfuzz --copt=-mllvm
+build:asan-honggfuzz --copt=-inline-threshold=2000
+build:asan-honggfuzz --copt=-fno-builtin
+build:asan-honggfuzz --copt=-fno-omit-frame-pointer
+build:asan-honggfuzz --copt=-D__NO_STRING_INLINES
+build:asan-honggfuzz --copt=-fsanitize=address
+build:asan-honggfuzz --copt=-fsanitize-coverage=trace-pc-guard,trace-cmp,trace-div,indirect-calls
+build:asan-honggfuzz --linkopt=-fsanitize=address
+build:asan-honggfuzz --//fuzzing:cc_engine=//fuzzing/engines:honggfuzz
+
 # Flags for Clang with MSAN and libfuzzer.
 build:msan-libfuzzer --config=_fuzzer_common
 build:msan-libfuzzer --linkopt=-fsanitize=memory,fuzzer
diff --git a/README.md b/README.md
index f661c46..a8f7f5c 100644
--- a/README.md
+++ b/README.md
@@ -14,6 +14,7 @@
 
 - `--config=asan-libfuzzer` builds the fuzz target in [libFuzzer](https://llvm.org/docs/LibFuzzer.html) mode, with [Address Sanitizer (ASAN)](https://clang.llvm.org/docs/AddressSanitizer.html) instrumentation.
 - `--config=msan-libfuzzer` builds the fuzz target in libFuzzer mode, with [Memory Sanitizer (MSAN)](https://clang.llvm.org/docs/MemorySanitizer.html) instrumentation.
+- `--config=asan-honggfuzz` builds the fuzz target using [Honggfuzz](https://github.com/google/honggfuzz), with ASAN instrumentation.
 
 The rest of the documentation assumes the build configuration options are accessible through these names.
 
@@ -68,24 +69,21 @@
 To run the fuzz target, use the following command:
 
 ```sh
-$ bazel run fuzz_test_run --config=libfuzzer
+$ bazel run fuzz_test_run --config=asan-libfuzzer
 ```
 
 You can also control the fuzzing test running time by passing `--timeout_secs` like
 
 ```sh
-$ bazel run fuzz_test_run --config=libfuzzer -- --timeout_secs=20
+$ bazel run fuzz_test_run --config=asan-libfuzzer -- --timeout_secs=20
 ```
 
 If you only want to run the regression test on the corpus, set `--regression`:
 
 ```sh
-$ bazel run fuzz_test_run --config=libfuzzer -- --regression=True
+$ bazel run fuzz_test_run --config=asan-libfuzzer -- --regression=True
 ```
 
-Feel free to copy the config setting in [.bazelrc](https://github.com/googleinterns/bazel-rules-fuzzing/blob/master/.bazelrc) to yours.
-
-
 See the [examples](https://github.com/googleinterns/bazel-rules-fuzzing/tree/master/examples)
 directory for more examples.
 
diff --git a/WORKSPACE b/WORKSPACE
index 909a868..262fb33 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -16,12 +16,15 @@
 
 # Downloads dependencies.
 load("@rules_fuzzing//fuzzing:repositories.bzl", "rules_fuzzing_dependencies")
+
 rules_fuzzing_dependencies()
 
 # Imports the transitive dependencies.
 load("@rules_fuzzing//fuzzing:dependency_imports.bzl", "fuzzing_dependency_imports")
+
 fuzzing_dependency_imports()
 
 # Installs python dependencies.
 load("@fuzzing_py_deps//:requirements.bzl", fuzzing_py_install = "pip_install")
+
 fuzzing_py_install()
diff --git a/examples/BUILD b/examples/BUILD
index e1e5f17..3055dec 100644
--- a/examples/BUILD
+++ b/examples/BUILD
@@ -18,11 +18,6 @@
 load("//fuzzing:cc_deps.bzl", "cc_fuzz_test")
 
 cc_fuzz_test(
-    name = "buffer_overflow_fuzz_test",
-    srcs = ["buffer_overflow_fuzz_test.cc"],
-)
-
-cc_fuzz_test(
     name = "empty_fuzz_test",
     srcs = ["empty_fuzz_test.cc"],
 )
@@ -71,6 +66,11 @@
     srcs = ["hang_fuzz_test.cc"],
 )
 
+cc_fuzz_test(
+    name = "input_buffer_overflow_fuzz_test",
+    srcs = ["input_buffer_overflow_fuzz_test.cc"],
+)
+
 # This test is designed to trigger an uninitialized memory issue.
 cc_fuzz_test(
     name = "msan_fuzz_test",
@@ -79,6 +79,11 @@
 )
 
 cc_fuzz_test(
+    name = "new_buffer_overflow_fuzz_test",
+    srcs = ["new_buffer_overflow_fuzz_test.cc"],
+)
+
+cc_fuzz_test(
     name = "oom_fuzz_test",
     srcs = ["oom_fuzz_test.cc"],
 )
diff --git a/examples/buffer_overflow_fuzz_test.cc b/examples/input_buffer_overflow_fuzz_test.cc
similarity index 92%
rename from examples/buffer_overflow_fuzz_test.cc
rename to examples/input_buffer_overflow_fuzz_test.cc
index 6b01ae6..e8e81f4 100644
--- a/examples/buffer_overflow_fuzz_test.cc
+++ b/examples/input_buffer_overflow_fuzz_test.cc
@@ -1,4 +1,3 @@
-//
 // Copyright 2020 Google LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +12,6 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// A fuzz target that causes an ASAN buffer overflow for a particular input.
-
 #include <cstdio>
 #include <cstdint>
 #include <cstddef>
diff --git a/examples/buffer_overflow_fuzz_test.cc b/examples/new_buffer_overflow_fuzz_test.cc
similarity index 85%
copy from examples/buffer_overflow_fuzz_test.cc
copy to examples/new_buffer_overflow_fuzz_test.cc
index 6b01ae6..8f2e6b8 100644
--- a/examples/buffer_overflow_fuzz_test.cc
+++ b/examples/new_buffer_overflow_fuzz_test.cc
@@ -1,4 +1,3 @@
-//
 // Copyright 2020 Google LLC
 //
 // Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,11 +12,10 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-// A fuzz target that causes an ASAN buffer overflow for a particular input.
-
 #include <cstdio>
 #include <cstdint>
 #include <cstddef>
+#include <cstring>
 
 void TriggerBufferOverflow(const uint8_t *data, size_t size) {
   if (size >= 3 &&
@@ -30,6 +28,9 @@
 }
 
 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
-  TriggerBufferOverflow(data, size);
+  uint8_t* data_copy = new uint8_t[size];
+  memcpy(data_copy, data, size);
+  TriggerBufferOverflow(data_copy, size);
+  delete []data_copy;
   return 0;
 }
diff --git a/fuzzing/dependency_imports.bzl b/fuzzing/dependency_imports.bzl
index b50e171..6914880 100644
--- a/fuzzing/dependency_imports.bzl
+++ b/fuzzing/dependency_imports.bzl
@@ -12,7 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-# Loads the dependencies of the external repositories
+"""Provides fuzzing dependencies."""
 
 load("@rules_python//python:pip.bzl", "pip3_import", "pip_repositories")
 load("@rules_python//python:repositories.bzl", "py_repositories")
diff --git a/fuzzing/engines/BUILD b/fuzzing/engines/BUILD
index fc187ba..1d5a08e 100644
--- a/fuzzing/engines/BUILD
+++ b/fuzzing/engines/BUILD
@@ -30,3 +30,17 @@
     name = "libfuzzer_stub",
     srcs = ["libfuzzer_stub.cc"],
 )
+
+# Honggfuzz specification.
+##########################
+
+cc_fuzzing_engine(
+    name = "honggfuzz",
+    data = {
+        "@honggfuzz//:honggfuzz": "HONGGFUZZ_PATH",
+    },
+    display_name = "Honggfuzz",
+    launcher = "honggfuzz_launcher.sh",
+    library = "@honggfuzz//:honggfuzz_engine",
+    visibility = ["//visibility:public"],
+)
diff --git a/fuzzing/engines/honggfuzz_launcher.sh b/fuzzing/engines/honggfuzz_launcher.sh
new file mode 100644
index 0000000..3bd5cdd
--- /dev/null
+++ b/fuzzing/engines/honggfuzz_launcher.sh
@@ -0,0 +1,36 @@
+# Copyright 2020 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.
+
+command_line="${HONGGFUZZ_PATH}"
+command_line+=("--workspace=${FUZZER_OUTPUT_ROOT}")
+
+if [[ -n "${FUZZER_SEED_CORPUS_DIR}" ]]; then
+    command_line+=("--input=${FUZZER_SEED_CORPUS_DIR}")
+    command_line+=("--output=${FUZZER_OUTPUT_CORPUS_DIR}")
+else
+    command_line+=("--input=${FUZZER_OUTPUT_CORPUS_DIR}")
+fi
+
+command_line+=("--crashdir=${FUZZER_ARTIFACTS_DIR}")
+
+if [[ "${FUZZER_TIMEOUT_SECS}" -gt 0 ]]; then
+    command_line+=("--run_time=${FUZZER_TIMEOUT_SECS}")
+fi
+
+if [[ -n "${FUZZER_DICTIONARY_PATH}" ]]; then
+    command_line+=("--dict=${FUZZER_DICTIONARY_PATH}")
+fi
+command_line+=("--" "${FUZZER_BINARY}")
+
+exec "${command_line[@]}"
diff --git a/fuzzing/repositories.bzl b/fuzzing/repositories.bzl
index 0ad1606..2063db1 100644
--- a/fuzzing/repositories.bzl
+++ b/fuzzing/repositories.bzl
@@ -42,3 +42,15 @@
         ],
         sha256 = "1c531376ac7e5a180e0237938a2536de0c54d93f5c278634818e0efc952dd56c",
     )
+
+    # TODO(sbucur): Since Honggfuzz has its own set of dependencies, look into
+    # making them optional, so developers only import them if they decide to
+    # use Honggfuzz.
+    maybe(
+        http_archive,
+        name = "honggfuzz",
+        build_file = "@//:honggfuzz.BUILD",
+        sha256 = "ec2a6c006da4d699252fafcc38c42c6759a045aa303a22dabaaa6c35330131aa",
+        url = "https://github.com/google/honggfuzz/archive/e2acee785aa87a86261c96070cf51b85533257ca.zip",
+        strip_prefix = "honggfuzz-e2acee785aa87a86261c96070cf51b85533257ca",
+    )
diff --git a/honggfuzz.BUILD b/honggfuzz.BUILD
new file mode 100644
index 0000000..52ec076
--- /dev/null
+++ b/honggfuzz.BUILD
@@ -0,0 +1,176 @@
+# Copyright 2020 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.
+
+# Bazel rules for building the Honggfuzz binary and the library linked with the
+# fuzz test executables.
+#
+# To use Honggfuzz, the following OS packages need to be installed:
+#   * libunwind-dev
+#   * libblocksruntime-dev
+#
+# NOTE: Currently, Honggfuzz is unable to detect buffer overflows in the input
+# string passed to the fuzz test entry point. This limitation is *not* caused
+# by the build options below limiting the use of sanitizers in the Honggfuzz
+# libraries.
+
+load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_library")
+
+COMMON_COPTS = [
+    "-D_GNU_SOURCE",
+    "-D_HF_ARCH_LINUX",
+    "-fPIC",
+    "-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",
+]
+
+LIBRARY_COPTS = [
+    "-fno-stack-protector",
+    "-U_FORTIFY_SOURCE",
+    "-D_FORTIFY_SOURCE=0",
+]
+
+# Linker options for intercepting common memory operations. Should stay in sync
+# with https://github.com/google/honggfuzz/blob/master/hfuzz_cc/hfuzz-cc.c
+SYMBOL_WRAP_LINKOPTS = [
+    # Intercept common *cmp functions.
+    "-Wl,--wrap=strcmp",
+    "-Wl,--wrap=strcasecmp",
+    "-Wl,--wrap=stricmp",
+    "-Wl,--wrap=strncmp",
+    "-Wl,--wrap=strncasecmp",
+    "-Wl,--wrap=strnicmp",
+    "-Wl,--wrap=strstr",
+    "-Wl,--wrap=strcasestr",
+    "-Wl,--wrap=memcmp",
+    "-Wl,--wrap=bcmp",
+    "-Wl,--wrap=memmem",
+    "-Wl,--wrap=strcpy",
+    # Apache httpd
+    "-Wl,--wrap=ap_cstr_casecmp",
+    "-Wl,--wrap=ap_cstr_casecmpn",
+    "-Wl,--wrap=ap_strcasestr",
+    "-Wl,--wrap=apr_cstr_casecmp",
+    "-Wl,--wrap=apr_cstr_casecmpn",
+    # *SSL
+    "-Wl,--wrap=CRYPTO_memcmp",
+    "-Wl,--wrap=OPENSSL_memcmp",
+    "-Wl,--wrap=OPENSSL_strcasecmp",
+    "-Wl,--wrap=OPENSSL_strncasecmp",
+    "-Wl,--wrap=memcmpct",
+    # libXML2
+    "-Wl,--wrap=xmlStrncmp",
+    "-Wl,--wrap=xmlStrcmp",
+    "-Wl,--wrap=xmlStrEqual",
+    "-Wl,--wrap=xmlStrcasecmp",
+    "-Wl,--wrap=xmlStrncasecmp",
+    "-Wl,--wrap=xmlStrstr",
+    "-Wl,--wrap=xmlStrcasestr",
+    # Samba
+    "-Wl,--wrap=memcmp_const_time",
+    "-Wl,--wrap=strcsequal",
+    # LittleCMS
+    "-Wl,--wrap=cmsstrcasecmp",
+    # GLib
+    "-Wl,--wrap=g_strcmp0",
+    "-Wl,--wrap=g_strcasecmp",
+    "-Wl,--wrap=g_strncasecmp",
+    "-Wl,--wrap=g_strstr_len",
+    "-Wl,--wrap=g_ascii_strcasecmp",
+    "-Wl,--wrap=g_ascii_strncasecmp",
+    "-Wl,--wrap=g_str_has_prefix",
+    "-Wl,--wrap=g_str_has_suffix",
+    # CUrl
+    "-Wl,--wrap=Curl_strcasecompare",
+    "-Wl,--wrap=curl_strequal",
+    "-Wl,--wrap=Curl_safe_strcasecompare",
+    "-Wl,--wrap=Curl_strncasecompare",
+    "-Wl,--wrap=curl_strnequal",
+]
+
+cc_library(
+    name = "honggfuzz_common",
+    srcs = glob(["libhfcommon/*.c"]),
+    hdrs = glob(["libhfcommon/*.h"]),
+    copts = COMMON_COPTS + LIBRARY_COPTS,
+)
+
+cc_library(
+    name = "honggfuzz_engine",
+    srcs = glob([
+        "libhfuzz/*.c",
+        "libhfuzz/*.h",
+        "*.h",
+    ]),
+    copts = COMMON_COPTS + LIBRARY_COPTS,
+    linkopts = SYMBOL_WRAP_LINKOPTS + [
+        "-ldl",
+        "-lpthread",
+        "-lrt",
+    ],
+    visibility = ["//visibility:public"],
+    deps = [
+        ":honggfuzz_common",
+    ],
+    alwayslink = 1,
+)
+
+cc_binary(
+    name = "honggfuzz",
+    srcs = glob([
+        "*.c",
+        "*.h",
+    ]) + glob([
+        "linux/*.c",
+        "linux/*.h",
+    ]),
+    copts = COMMON_COPTS + [
+        "-D_HF_LINUX_NO_BFD",
+    ],
+    includes = [
+        ".",
+        "linux",
+    ],
+    # Consider linking statically with
+    # -l:libunwind-ptrace.a and -l:libunwind-generic.a.
+    linkopts = [
+        "-lpthread",
+        "-lunwind-ptrace",
+        "-lunwind-generic",
+        "-lunwind",
+        "-lrt",
+        "-llzma",
+        "-Wl,-Bstatic",
+        "-lBlocksRuntime",
+        "-Wl,-Bdynamic",
+    ],
+    linkstatic = 1,
+    visibility = ["//visibility:public"],
+    deps = [
+        ":honggfuzz_common",
+    ],
+)