Build fuzzer tests in standalone builds too.
This will avoid compilation to break, and adds standalone reproducers
for the fuzzer_tests.
BUG=chromium:903380
BUG=dawn:34
Change-Id: I9995a852076d9f6d1ebdee5b999989c2d74d4709
Reviewed-on: https://dawn-review.googlesource.com/c/2321
Commit-Queue: Corentin Wallez <cwallez@chromium.org>
Reviewed-by: Ryan Harrison <rharrison@chromium.org>
Reviewed-by: Dan Sinclair <dsinclair@google.com>
diff --git a/BUILD.gn b/BUILD.gn
index 12efda6..cc0fc28 100644
--- a/BUILD.gn
+++ b/BUILD.gn
@@ -17,9 +17,6 @@
import("//build_overrides/build.gni")
import("//testing/test.gni")
-if (build_with_chromium) {
- import("//testing/libfuzzer/fuzzer_test.gni")
-}
###############################################################################
# Template to wrap the Dawn code generator
@@ -948,100 +945,16 @@
###############################################################################
# Fuzzers
###############################################################################
-if (build_with_chromium) {
- group("dawn_fuzzers") {
- testonly = true
- deps = [
- ":dawn_spirv_cross_glsl_fast_fuzzer",
- ":dawn_spirv_cross_glsl_full_fuzzer",
- ":dawn_spirv_cross_hlsl_fast_fuzzer",
- ":dawn_spirv_cross_hlsl_full_fuzzer",
- ":dawn_spirv_cross_msl_fast_fuzzer",
- ":dawn_spirv_cross_msl_full_fuzzer",
- ]
- }
- static_library("dawn_spirv_cross_fuzzer_common") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossFuzzer.cpp",
- "src/fuzzers/DawnSPIRVCrossFuzzer.h",
- ]
- public_deps = [
- "third_party:spirv_cross",
- ]
- }
-
- # Uses Dawn specific options and varies input data
- fuzzer_test("dawn_spirv_cross_glsl_fast_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- # Varies bother the options and input data
- fuzzer_test("dawn_spirv_cross_glsl_full_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- # Uses Dawn specific options and varies input data
- fuzzer_test("dawn_spirv_cross_hlsl_fast_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- # Varies bother the options and input data
- fuzzer_test("dawn_spirv_cross_hlsl_full_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- # Uses Dawn specific options and varies input data
- fuzzer_test("dawn_spirv_cross_msl_fast_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- # Varies bother the options and input data
- fuzzer_test("dawn_spirv_cross_msl_full_fuzzer") {
- sources = [
- "src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp",
- ]
- deps = [
- ":dawn_spirv_cross_fuzzer_common",
- ]
- }
-
- fuzzer_test("dawn_wire_server_and_frontend_fuzzer") {
- sources = [
- "src/fuzzers/DawnWireServerAndFrontendFuzzer.cpp",
- ]
-
- deps = [
- ":libdawn",
- ":libdawn_native",
- ":libdawn_wire",
- ]
-
- additional_configs = [ ":dawn_shared_library_public" ]
- }
+group("dawn_fuzzers") {
+ testonly = true
+ deps = [
+ "src/fuzzers:dawn_spirv_cross_glsl_fast_fuzzer",
+ "src/fuzzers:dawn_spirv_cross_glsl_full_fuzzer",
+ "src/fuzzers:dawn_spirv_cross_hlsl_fast_fuzzer",
+ "src/fuzzers:dawn_spirv_cross_hlsl_full_fuzzer",
+ "src/fuzzers:dawn_spirv_cross_msl_fast_fuzzer",
+ "src/fuzzers:dawn_spirv_cross_msl_full_fuzzer",
+ "src/fuzzers:dawn_wire_server_and_frontend_fuzzer",
+ ]
}
diff --git a/src/fuzzers/BUILD.gn b/src/fuzzers/BUILD.gn
new file mode 100644
index 0000000..9680d6e
--- /dev/null
+++ b/src/fuzzers/BUILD.gn
@@ -0,0 +1,150 @@
+# Copyright 2018 The Dawn 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
+#
+# http://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.
+
+import("//build_overrides/build.gni")
+
+dawn_top_level = "../.."
+
+# We only have libfuzzer in Chromium builds but if we build fuzzer targets only
+# there, we would risk breaking fuzzer targets all the time when making changes
+# to Dawn. To avoid that, we make fuzzer targets compile in standalone builds
+# as well with a dawn_fuzzer_test target that acts like Chromium's fuzzer_test.
+#
+# The standalone fuzzer targets are able to run a single fuzzer input which
+# could help reproduce fuzzer crashes more easily because you don't need a
+# whole Chromium checkout.
+
+if (build_with_chromium) {
+ import("//testing/libfuzzer/fuzzer_test.gni")
+
+ # In Chromium build we just proxy everything to the real fuzzer_test
+ template("dawn_fuzzer_test") {
+ fuzzer_test(target_name) {
+ forward_variables_from(invoker, "*")
+ }
+ }
+} else {
+ import("//testing/test.gni")
+
+ # In standalone build we do something similar to fuzzer_test.
+ template("dawn_fuzzer_test") {
+ test(target_name) {
+ forward_variables_from(invoker,
+ [
+ "cflags",
+ "cflags_cc",
+ "check_includes",
+ "defines",
+ "deps",
+ "include_dirs",
+ "sources",
+ ])
+
+ if (!defined(configs)) {
+ configs = []
+ }
+
+ # Weirdly fuzzer_test uses a special variable for additional configs.
+ if (defined(invoker.additional_configs)) {
+ configs += invoker.additional_configs
+ }
+
+ sources += [ "StandaloneFuzzerMain.cpp" ]
+ }
+ }
+}
+
+static_library("dawn_spirv_cross_fuzzer_common") {
+ sources = [
+ "DawnSPIRVCrossFuzzer.cpp",
+ "DawnSPIRVCrossFuzzer.h",
+ ]
+ public_deps = [
+ "${dawn_top_level}/third_party:spirv_cross",
+ ]
+}
+
+# Uses Dawn specific options and varies input data
+dawn_fuzzer_test("dawn_spirv_cross_glsl_fast_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFastFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+# Varies bother the options and input data
+dawn_fuzzer_test("dawn_spirv_cross_glsl_full_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFullFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+# Uses Dawn specific options and varies input data
+dawn_fuzzer_test("dawn_spirv_cross_hlsl_fast_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFastFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+# Varies bother the options and input data
+dawn_fuzzer_test("dawn_spirv_cross_hlsl_full_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFullFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+# Uses Dawn specific options and varies input data
+dawn_fuzzer_test("dawn_spirv_cross_msl_fast_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFastFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+# Varies bother the options and input data
+dawn_fuzzer_test("dawn_spirv_cross_msl_full_fuzzer") {
+ sources = [
+ "DawnSPIRVCrossGLSLFullFuzzer.cpp",
+ ]
+ deps = [
+ ":dawn_spirv_cross_fuzzer_common",
+ ]
+}
+
+dawn_fuzzer_test("dawn_wire_server_and_frontend_fuzzer") {
+ sources = [
+ "DawnWireServerAndFrontendFuzzer.cpp",
+ ]
+
+ deps = [
+ "${dawn_top_level}:libdawn",
+ "${dawn_top_level}:libdawn_native",
+ "${dawn_top_level}:libdawn_wire",
+ ]
+
+ additional_configs = [ "${dawn_top_level}:dawn_shared_library_public" ]
+}
diff --git a/src/fuzzers/StandaloneFuzzerMain.cpp b/src/fuzzers/StandaloneFuzzerMain.cpp
new file mode 100644
index 0000000..ba8d94b
--- /dev/null
+++ b/src/fuzzers/StandaloneFuzzerMain.cpp
@@ -0,0 +1,62 @@
+// Copyright 2018 The Dawn 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
+//
+// http://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.
+
+#include <cstdint>
+#include <cstdlib>
+#include <iostream>
+#include <vector>
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size);
+
+int main(int argc, char** argv) {
+ if (argc != 2) {
+ std::cout << "Usage: <standalone reproducer> [FILE]" << std::endl;
+ return 1;
+ }
+
+ std::cout << "WARNING: this is just a best-effort reproducer for fuzzer issues in standalone "
+ << "Dawn builds. For the real fuzzer, please build inside Chromium." << std::endl;
+
+ const char* filename = argv[1];
+ std::cout << "Reproducing using file: " << filename << std::endl;
+
+ std::vector<char> data;
+ {
+ FILE* file = fopen(filename, "rb");
+ if (!file) {
+ std::cerr << "Failed to open " << filename << std::endl;
+ return 1;
+ }
+
+ fseek(file, 0, SEEK_END);
+ long tellFileSize = ftell(file);
+ if (tellFileSize <= 0) {
+ std::cerr << "Input file of incorrect size: " << filename << std::endl;
+ return 1;
+ }
+ fseek(file, 0, SEEK_SET);
+
+ size_t fileSize = static_cast<size_t>(tellFileSize);
+ data.resize(fileSize);
+
+ size_t bytesRead = fread(data.data(), sizeof(char), fileSize, file);
+ fclose(file);
+ if (bytesRead != fileSize) {
+ std::cerr << "Failed to read " << filename << std::endl;
+ return 1;
+ }
+ }
+
+ return LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t*>(data.data()), data.size());
+}