diff --git a/BUILD.gn b/BUILD.gn index cc743e10e4..3e6898b4ea 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -17,6 +17,9 @@ import("scripts/dawn_features.gni") 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 @@ -941,3 +944,99 @@ if (dawn_standalone) { ] } } + +############################################################################### +# 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", + ] + } + + config("dawn_spirv_cross_fuzzers_config") { + defines = [ "SPIRV_CROSS_EXCEPTIONS_TO_ASSERTIONS" ] + include_dirs = [ + "src/fuzzers", + "third_party/", + ] + } + + static_library("dawn_spirv_cross_fuzzer_common") { + public_configs = [ ":dawn_spirv_cross_fuzzers_config" ] + sources = [ + "src/fuzzers/DawnSPIRVCrossFuzzer.cpp", + "src/fuzzers/DawnSPIRVCrossFuzzer.h", + ] + 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", + ] + } +} diff --git a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp index c4bd12e245..ad1c5068ad 100644 --- a/src/dawn_native/d3d12/ShaderModuleD3D12.cpp +++ b/src/dawn_native/d3d12/ShaderModuleD3D12.cpp @@ -33,6 +33,8 @@ namespace dawn_native { namespace d3d12 { const std::string ShaderModule::GetHLSLSource(PipelineLayout* layout) const { spirv_cross::CompilerHLSL compiler(mSpirv); + // If these options are changed, the values in DawnSPIRVCrossHLSLFastFuzzer.cpp need to be + // updated. spirv_cross::CompilerGLSL::Options options_glsl; options_glsl.vertex.fixup_clipspace = true; options_glsl.vertex.flip_vert_y = true; diff --git a/src/dawn_native/metal/ShaderModuleMTL.mm b/src/dawn_native/metal/ShaderModuleMTL.mm index bf55ca8ec7..2d38d1854f 100644 --- a/src/dawn_native/metal/ShaderModuleMTL.mm +++ b/src/dawn_native/metal/ShaderModuleMTL.mm @@ -52,6 +52,8 @@ namespace dawn_native { namespace metal { const PipelineLayout* layout) const { spirv_cross::CompilerMSL compiler(mSpirv); + // If these options are changed, the values in DawnSPIRVCrossMSLFastFuzzer.cpp need to be + // updated. spirv_cross::CompilerGLSL::Options options_glsl; options_glsl.vertex.flip_vert_y = true; compiler.spirv_cross::CompilerGLSL::set_common_options(options_glsl); diff --git a/src/dawn_native/opengl/ShaderModuleGL.cpp b/src/dawn_native/opengl/ShaderModuleGL.cpp index d607bef1cb..ab24940bd0 100644 --- a/src/dawn_native/opengl/ShaderModuleGL.cpp +++ b/src/dawn_native/opengl/ShaderModuleGL.cpp @@ -50,6 +50,8 @@ namespace dawn_native { namespace opengl { ShaderModule::ShaderModule(Device* device, const ShaderModuleDescriptor* descriptor) : ShaderModuleBase(device, descriptor) { spirv_cross::CompilerGLSL compiler(descriptor->code, descriptor->codeSize); + // If these options are changed, the values in DawnSPIRVCrossGLSLFastFuzzer.cpp need to be + // updated. spirv_cross::CompilerGLSL::Options options; // TODO(cwallez@chromium.org): discover the backing context version and use that. diff --git a/src/fuzzers/DawnSPIRVCrossFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossFuzzer.cpp new file mode 100644 index 0000000000..55b340a7fe --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossFuzzer.cpp @@ -0,0 +1,112 @@ +// 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 +#include +#include +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +namespace { + + std::jmp_buf jump_buffer; + void (*old_signal_handler)(int); + + // Handler to trap signals, so that it doesn't crash the fuzzer when running + // the code under test. Currently the + // code being fuzzed uses abort() to report errors like bad input instead of + // returning an error code. This will be changing in the future. + // + // TODO(rharrison): Remove all of this signal trapping once SPIRV-Cross has + // been changed to not use abort() for reporting errors. + [[noreturn]] static void sigabrt_trap(int sig) { + std::longjmp(jump_buffer, 1); + } + + // Setup the SIGABRT trap + void BeginSIGABRTTrap() { + old_signal_handler = signal(SIGABRT, sigabrt_trap); + if (old_signal_handler == SIG_ERR) + abort(); + } + + // Restore the previous signal handler + void EndSIGABRTTrap() { + signal(SIGABRT, old_signal_handler); + } + +} // namespace + +namespace DawnSPIRVCrossFuzzer { + + int Run(const uint8_t* data, size_t size, std::function)> task) { + if (!data || size < 1) + return 0; + + std::vector input(data, data + (4 * (size / 4))); + + BeginSIGABRTTrap(); + + // On the first pass through setjmp will return 0, if returning here + // from the longjmp in the signal handler it will return 1. + if (setjmp(jump_buffer) == 0) { + task(input); + } + + EndSIGABRTTrap(); + + return 0; + } + + template + int RunWithOptions(const uint8_t* data, + size_t size, + std::function, Options)> task) { + if (!data || size < sizeof(Options) + 1) + return 0; + + Options options = *reinterpret_cast(data); + data += sizeof(options); + size -= sizeof(options); + + std::vector input(data, data + (4 * (size / 4))); + + BeginSIGABRTTrap(); + + // On the first pass through setjmp will return 0, if returning here + // from the longjmp in the signal handler it will return 1. + if (setjmp(jump_buffer) == 0) { + task(input, options); + } + + EndSIGABRTTrap(); + + return 0; + } + + template int RunWithOptions( + const uint8_t*, + size_t, + TaskWithOptions); + template int RunWithOptions( + const uint8_t*, + size_t, + TaskWithOptions); + template int RunWithOptions(const uint8_t*, + size_t, + TaskWithOptions); + +} // namespace DawnSPIRVCrossFuzzer diff --git a/src/fuzzers/DawnSPIRVCrossFuzzer.h b/src/fuzzers/DawnSPIRVCrossFuzzer.h new file mode 100644 index 0000000000..d6cebbc845 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossFuzzer.h @@ -0,0 +1,40 @@ +// 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 +#include +#include + +#include "spirv-cross/spirv_glsl.hpp" +#include "spirv-cross/spirv_hlsl.hpp" + +namespace DawnSPIRVCrossFuzzer { + + struct CombinedOptions { + spirv_cross::CompilerGLSL::Options glsl; + spirv_cross::CompilerHLSL::Options hlsl; + }; + + using Task = std::function)>; + template + using TaskWithOptions = std::function, Options)>; + + // Used to fuzz by mutating the input data, but with fixed options to the compiler + int Run(const uint8_t* data, size_t size, Task task); + + // Used to fuzz by mutating both the input data and options to the compiler + template + int RunWithOptions(const uint8_t* data, size_t size, TaskWithOptions task); + +} // namespace DawnSPIRVCrossFuzzer diff --git a/src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp new file mode 100644 index 0000000000..1959612d03 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossGLSLFastFuzzer.cpp @@ -0,0 +1,39 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +namespace { + + int GLSLFastFuzzTask(std::vector input) { + spirv_cross::CompilerGLSL compiler(input); + + // Using the options that are used by Dawn, they appear in ShaderModuleGL.cpp + spirv_cross::CompilerGLSL::Options options; + options.version = 440; + compiler.set_common_options(options); + + std::string result = compiler.compile(); + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::Run(data, size, GLSLFastFuzzTask); +} diff --git a/src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp new file mode 100644 index 0000000000..9784670890 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossGLSLFullFuzzer.cpp @@ -0,0 +1,37 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +namespace { + + int GLSLFullFuzzTask(std::vector input, spirv_cross::CompilerGLSL::Options options) { + spirv_cross::CompilerGLSL compiler(input); + compiler.set_common_options(options); + + std::string result = compiler.compile(); + + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::RunWithOptions( + data, size, GLSLFullFuzzTask); +} diff --git a/src/fuzzers/DawnSPIRVCrossHLSLFastFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossHLSLFastFuzzer.cpp new file mode 100644 index 0000000000..85e83e7487 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossHLSLFastFuzzer.cpp @@ -0,0 +1,46 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +#include "spirv-cross/spirv_hlsl.hpp" + +namespace { + + int FuzzTask(std::vector input) { + spirv_cross::CompilerHLSL compiler(input); + + // Using the options that are used by Dawn, they appear in ShaderModuleD3D12.cpp + spirv_cross::CompilerGLSL::Options options_glsl; + options_glsl.vertex.fixup_clipspace = true; + options_glsl.vertex.flip_vert_y = true; + compiler.set_common_options(options_glsl); + + spirv_cross::CompilerHLSL::Options options_hlsl; + options_hlsl.shader_model = 51; + compiler.set_hlsl_options(options_hlsl); + + std::string result = compiler.compile(); + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask); +} diff --git a/src/fuzzers/DawnSPIRVCrossHLSLFullFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossHLSLFullFuzzer.cpp new file mode 100644 index 0000000000..1985d2afb0 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossHLSLFullFuzzer.cpp @@ -0,0 +1,39 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +#include "spirv-cross/spirv_hlsl.hpp" + +namespace { + int FuzzTask(std::vector input, DawnSPIRVCrossFuzzer::CombinedOptions options) { + spirv_cross::CompilerHLSL compiler(input); + + compiler.set_common_options(options.glsl); + compiler.set_hlsl_options(options.hlsl); + + std::string result = compiler.compile(); + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::RunWithOptions(data, size, + FuzzTask); +} diff --git a/src/fuzzers/DawnSPIRVCrossMSLFastFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossMSLFastFuzzer.cpp new file mode 100644 index 0000000000..349d770dc5 --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossMSLFastFuzzer.cpp @@ -0,0 +1,41 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +#include "spirv-cross/spirv_msl.hpp" + +namespace { + + int FuzzTask(std::vector input) { + spirv_cross::CompilerMSL compiler(input); + + // Using the options that are used by Dawn, they appear in ShaderModuleMTL.mm + spirv_cross::CompilerGLSL::Options options; + options.vertex.flip_vert_y = true; + compiler.spirv_cross::CompilerGLSL::set_common_options(options); + + std::string result = compiler.compile(); + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::Run(data, size, FuzzTask); +} diff --git a/src/fuzzers/DawnSPIRVCrossMSLFullFuzzer.cpp b/src/fuzzers/DawnSPIRVCrossMSLFullFuzzer.cpp new file mode 100644 index 0000000000..1aaf3b0f6f --- /dev/null +++ b/src/fuzzers/DawnSPIRVCrossMSLFullFuzzer.cpp @@ -0,0 +1,39 @@ +// 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 +#include +#include + +#include "DawnSPIRVCrossFuzzer.h" + +#include "spirv-cross/spirv_msl.hpp" + +namespace { + + int FuzzTask(std::vector input, spirv_cross::CompilerGLSL::Options options) { + spirv_cross::CompilerMSL compiler(input); + + compiler.spirv_cross::CompilerGLSL::set_common_options(options); + + std::string result = compiler.compile(); + return 0; + } + +} // namespace + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + return DawnSPIRVCrossFuzzer::RunWithOptions(data, size, + FuzzTask); +} diff --git a/third_party/BUILD.gn b/third_party/BUILD.gn index 83b2c69974..fbec83675f 100644 --- a/third_party/BUILD.gn +++ b/third_party/BUILD.gn @@ -16,6 +16,10 @@ import("../scripts/dawn_overrides_with_defaults.gni") import("../scripts/dawn_features.gni") import("//build_overrides/build.gni") +if (build_with_chromium) { + import("//testing/libfuzzer/fuzzer_test.gni") +} + is_msvc = is_win && !is_clang ############################################################################### @@ -68,7 +72,12 @@ static_library("spirv_cross") { need_glsl_cross = dawn_enable_opengl - if (dawn_enable_d3d12) { + is_fuzzing = false + if (build_with_chromium) { + is_fuzzing = use_fuzzing_engine + } + + if (dawn_enable_d3d12 || is_fuzzing) { sources += [ "${spirv_cross_dir}/spirv_hlsl.cpp", "${spirv_cross_dir}/spirv_hlsl.hpp", @@ -76,7 +85,7 @@ static_library("spirv_cross") { need_glsl_cross = true } - if (dawn_enable_metal) { + if (dawn_enable_metal || is_fuzzing) { sources += [ "${spirv_cross_dir}/spirv_msl.cpp", "${spirv_cross_dir}/spirv_msl.hpp", @@ -84,7 +93,7 @@ static_library("spirv_cross") { need_glsl_cross = true } - if (need_glsl_cross) { + if (need_glsl_cross || is_fuzzing) { sources += [ "${spirv_cross_dir}/spirv_glsl.cpp", "${spirv_cross_dir}/spirv_glsl.hpp",