pw_fuzzer: Fix fuzz target unit tests
The path for the fuzzer unit test source was not source absolute.
Additionally, we need to provide a stub implementation of
FuzzedDataProvider when not using clang.
Change-Id: I440125b5aa86b6c1d1a194c399d8de6f53f58d48
diff --git a/pw_fuzzer/BUILD.gn b/pw_fuzzer/BUILD.gn
index 36f4cb4..479fcb8 100644
--- a/pw_fuzzer/BUILD.gn
+++ b/pw_fuzzer/BUILD.gn
@@ -21,8 +21,12 @@
pw_sanitizer = ""
}
+config("default_config") {
+ include_dirs = [ "public" ]
+}
+
# This is added automatically by the `pw_fuzzer` template.
-config("pw_fuzzer") {
+config("fuzzing") {
common_flags = [ "-fsanitize=fuzzer" ]
if (pw_sanitizer != "") {
common_flags += [ "-fsanitize=$pw_sanitizer" ]
@@ -31,6 +35,22 @@
ldflags = common_flags
}
+source_set("pw_fuzzer") {
+ public_configs = [ ":default_config" ]
+ public = [ "public/pw_fuzzer/fuzzed_data_provider.h" ]
+ sources = public
+ public_deps = [ "$dir_pw_log" ]
+}
+
+# See https://llvm.org/docs/LibFuzzer.html#fuzzer-friendly-build-mode
+config("fuzzing_build_mode_unsafe_for_production") {
+ defines = [ "FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION" ]
+}
+
+config("fuzzing_verbose_logging") {
+ defines = [ "FUZZING_VERBOSE_LOGGING" ]
+}
+
pw_doc_group("docs") {
inputs = [ "doc_resources/pw_fuzzer_coverage_guided.png" ]
sources = [ "docs.rst" ]
diff --git a/pw_fuzzer/fuzzer.gni b/pw_fuzzer/fuzzer.gni
index 4e0eefb..07f9562 100644
--- a/pw_fuzzer/fuzzer.gni
+++ b/pw_fuzzer/fuzzer.gni
@@ -39,7 +39,10 @@
configs = []
forward_variables_from(invoker, "*", [ "visibility" ])
forward_variables_from(invoker, [ "visibility" ])
- configs += [ "$dir_pw_fuzzer" ]
+ configs += [
+ "$dir_pw_fuzzer:default_config",
+ "$dir_pw_fuzzer:fuzzing",
+ ]
}
# Dummy target to satisfy `pw_test_group`. It is empty as we don't want to
@@ -50,10 +53,12 @@
# Build a unit test that exercise the fuzz target function.
pw_test(target_name) {
sources = []
+ configs = []
deps = []
forward_variables_from(invoker, "*", [ "visibility" ])
forward_variables_from(invoker, [ "visibility" ])
- sources += [ "pw_fuzzer_disabled.cc" ]
+ sources += [ "$dir_pw_fuzzer/pw_fuzzer_disabled.cc" ]
+ configs += [ "$dir_pw_fuzzer:default_config" ]
deps += [
"$dir_pw_log",
"$dir_pw_unit_test",
diff --git a/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h b/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h
new file mode 100644
index 0000000..a136da2
--- /dev/null
+++ b/pw_fuzzer/public/pw_fuzzer/fuzzed_data_provider.h
@@ -0,0 +1,139 @@
+// Copyright 2020 The Pigweed Authors
+//
+// 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.
+
+// Simply forwards to <fuzzer/FuzzedDataProvider.h> when available from clang,
+// or provides a simple stub implementation.
+#pragma once
+
+#if defined(__clang__)
+#include <fuzzer/FuzzedDataProvider.h>
+#else // !defined(__clang__)
+
+// If a fuzzer wants to use FuzzedDataProvider to build a fuzz target unit
+// test without clang, it can use this trivial class with the same signature.
+// The behavior will NOT be the same as a fuzzer unit test built by clang for
+// non-trivial inputs. This means non-clang fuzzer unit tests will not be
+// effective regression tests if given a seed corpus. These non-clang tests are
+// still useful, however, as they will guarantee the fuzzer code can compile and
+// link.
+//
+// The methods of this class are intentionally undocumented. To see the
+// documentation for each, consult the real header file, e.g. in
+// .cipd/pigweed/lib/clang/11.0.0/include/fuzzer/FuzzedDataProvider.h
+#include <cstddef>
+#include <cstdint>
+#include <string>
+#include <vector>
+
+#include "pw_log/log.h"
+
+class FuzzedDataProvider {
+ public:
+ FuzzedDataProvider(const uint8_t* data, size_t size) {
+ PW_UNUSED(data);
+ PW_UNUSED(size);
+ PW_LOG_INFO("Fuzzing is disabled for the current compiler.");
+ PW_LOG_INFO("Using trivial stub implementation for FuzzedDataProvider.");
+ }
+
+ ~FuzzedDataProvider() = default;
+
+ template <typename T>
+ std::vector<T> ConsumeBytes(size_t num_bytes) {
+ PW_UNUSED(num_bytes);
+ return std::vector<T>{};
+ }
+
+ template <typename T>
+ std::vector<T> ConsumeBytesWithTerminator(size_t num_bytes,
+ T terminator = 0) {
+ PW_UNUSED(num_bytes);
+ return std::vector<T>{terminator};
+ }
+
+ template <typename T>
+ std::vector<T> ConsumeRemainingBytes() {
+ return std::vector<T>{};
+ }
+
+ std::string ConsumeBytesAsString(size_t num_bytes) {
+ PW_UNUSED(num_bytes);
+ return std::string{};
+ }
+
+ std::string ConsumeRandomLengthString(size_t max_length) {
+ PW_UNUSED(max_length);
+ return std::string{};
+ }
+
+ std::string ConsumeRandomLengthString() { return std::string{}; }
+
+ std::string ConsumeRemainingBytesAsString() { return std::string{}; }
+
+ template <typename T>
+ T ConsumeIntegral() {
+ return T(0);
+ }
+
+ template <typename T>
+ T ConsumeIntegralInRange(T min, T max) {
+ PW_UNUSED(max);
+ return T(min);
+ }
+
+ template <typename T>
+ T ConsumeFloatingPoint() {
+ return T(0.0);
+ }
+
+ template <typename T>
+ T ConsumeFloatingPointInRange(T min, T max) {
+ PW_UNUSED(max);
+ return T(min);
+ }
+
+ template <typename T>
+ T ConsumeProbability() {
+ return T(0.0);
+ }
+
+ bool ConsumeBool() { return false; }
+
+ template <typename T>
+ T ConsumeEnum() {
+ return static_cast<T>(0);
+ }
+
+ template <typename T, size_t size>
+ T PickValueInArray(const T (&array)[size]) {
+ static_assert(size > 0, "The array must be non empty.");
+ return array[0];
+ }
+
+ template <typename T>
+ T PickValueInArray(std::initializer_list<const T> list) {
+ static_assert(list.size() > 0, "The list must be non empty.");
+ return *list.begin();
+ }
+
+ size_t ConsumeData(void* destination, size_t num_bytes) {
+ PW_UNUSED(destination);
+ PW_UNUSED(num_bytes);
+ return 0;
+ }
+
+ size_t remaining_bytes() { return 0; }
+};
+
+#endif // defined(__clang__)
diff --git a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
index 55b157c..5cee92b 100755
--- a/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
+++ b/pw_presubmit/py/pw_presubmit/pigweed_presubmit.py
@@ -438,7 +438,7 @@
missing_gn.append(path)
# TODO(pwbug/176) Replace this workaround for fuzzers.
- missing_bazel = [p for p in missing_bazel if 'fuzzer' not in p.name]
+ missing_bazel = [p for p in missing_bazel if 'fuzz' not in p.name]
if missing_bazel or missing_gn:
for build, files in [('Bazel', missing_bazel), ('GN', missing_gn)]: