From d0b284b00b93113dc981e18fe56502edb71b6790 Mon Sep 17 00:00:00 2001 From: Brendon Tiszka Date: Wed, 8 Feb 2023 20:43:18 +0000 Subject: [PATCH] Add Dawn Wire Server LPM Fuzzer [1/N] Add scaffolding for structured Dawn wire fuzzer. This CL contains a basic fuzzer for Dawn wire server that shows some simple design ideas: 1) A basic protobuf spec that is generated using dawn.json 2) conversion from protobuf message to a dawn wire server command. This is not the complete implementation and serves as a foundation for the fuzzer so that subsequent CLs will be easier to review. Bug: chromium:1374747 Change-Id: Ife1642dda13d01d3308bdd5fe56cf85978399fd3 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/109406 Reviewed-by: Corentin Wallez Kokoro: Kokoro Reviewed-by: Austin Eng Commit-Queue: Brendon Tiszka --- docs/dawn/codegen.md | 9 ++ generator/dawn_generator.gni | 22 +++ generator/dawn_json_generator.py | 53 ++++++- .../fuzzers/lpmfuzz/DawnLPMSerializer.cpp | 50 +++++++ .../dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h | 46 ++++++ .../dawn/fuzzers/lpmfuzz/dawn_lpm.proto | 32 +++++ src/dawn/fuzzers/BUILD.gn | 67 ++++++++- src/dawn/fuzzers/dawn_fuzzers.gni | 19 +++ src/dawn/fuzzers/lpmfuzz/DawnLPMConstants.h | 15 ++ src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.cpp | 133 ++++++++++++++++++ src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h | 34 +++++ .../lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp | 33 +++++ src/dawn/fuzzers/lpmfuzz/dawn_lpm.json | 19 +++ 13 files changed, 530 insertions(+), 2 deletions(-) create mode 100644 generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp create mode 100644 generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h create mode 100644 generator/templates/dawn/fuzzers/lpmfuzz/dawn_lpm.proto create mode 100644 src/dawn/fuzzers/dawn_fuzzers.gni create mode 100644 src/dawn/fuzzers/lpmfuzz/DawnLPMConstants.h create mode 100644 src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.cpp create mode 100644 src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h create mode 100644 src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp create mode 100644 src/dawn/fuzzers/lpmfuzz/dawn_lpm.json diff --git a/docs/dawn/codegen.md b/docs/dawn/codegen.md index 1bded3f7a7..359fddea7e 100644 --- a/docs/dawn/codegen.md +++ b/docs/dawn/codegen.md @@ -111,3 +111,12 @@ The schema of `dawn_wire.json` is a dictionary with the following keys: ## OpenGL loader generator The code to load OpenGL entrypoints from a `GetProcAddress` function is generated from [`gl.xml`](../third_party/khronos/gl.xml) and the [list of extensions](../src/dawn/native/opengl/supported_extensions.json) it supports. + + +## Dawn lpmfuzz generator +One of Dawn's Fuzzers utilizes the information in [`dawn.json`, `dawn_wire.json`, `dawn_lpm.json`] to generate the `.proto` and `.cpp` files required for a [libprotobuf-mutator fuzzer](https://github.com/google/libprotobuf-mutator) that fuzzes Dawn Wire Server's stack with more effectiveness in some areas than plain libfuzzer. + +At this time it is used to generate: + + - the `dawn_lpm.proto` file used to describe the grammar for the fuzzer + - the serializer `DawnLPMSerializer.cpp` that takes an arbitrary number of protobuf structures that were defined in `dawn_lpm.proto` and serializes them to be passed to `DawnWireServer::HandleCommands`. diff --git a/generator/dawn_generator.gni b/generator/dawn_generator.gni index 9b6183f504..6a4e09078e 100644 --- a/generator/dawn_generator.gni +++ b/generator/dawn_generator.gni @@ -80,3 +80,25 @@ template("dawn_json_generator") { forward_variables_from(invoker, "*", [ "target" ]) } } + +template("dawn_json_lpm_generator") { + dawn_generator(target_name) { + script = "${dawn_root}/generator/dawn_json_generator.py" + + # The base arguments for the generator: from this dawn.json, generate this + # target using templates in this directory. + args = [ + "--dawn-json", + rebase_path("${dawn_root}/dawn.json", root_build_dir), + "--wire-json", + rebase_path("${dawn_root}/dawn_wire.json", root_build_dir), + "--lpm-json", + rebase_path("${dawn_root}/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json", + root_build_dir), + "--targets", + invoker.target, + ] + + forward_variables_from(invoker, "*", [ "target" ]) + } +} diff --git a/generator/dawn_json_generator.py b/generator/dawn_json_generator.py index e818d2a2e9..8eb0d6c98a 100644 --- a/generator/dawn_json_generator.py +++ b/generator/dawn_json_generator.py @@ -777,7 +777,7 @@ class MultiGeneratorFromDawnJSON(Generator): def add_commandline_arguments(self, parser): allowed_targets = [ 'dawn_headers', 'cpp_headers', 'cpp', 'proc', 'mock_api', 'wire', - 'native_utils' + 'native_utils', 'dawn_lpmfuzz_cpp', 'dawn_lpmfuzz_proto' ] parser.add_argument('--dawn-json', @@ -788,6 +788,10 @@ class MultiGeneratorFromDawnJSON(Generator): default=None, type=str, help='The DAWN WIRE JSON definition to use.') + parser.add_argument("--lpm-json", + default=None, + type=str, + help='The DAWN LPM FUZZER definitions to use.') parser.add_argument( '--targets', required=True, @@ -795,6 +799,7 @@ class MultiGeneratorFromDawnJSON(Generator): help= 'Comma-separated subset of targets to output. Available targets: ' + ', '.join(allowed_targets)) + def get_file_renders(self, args): with open(args.dawn_json) as f: loaded_json = json.loads(f.read()) @@ -806,6 +811,11 @@ class MultiGeneratorFromDawnJSON(Generator): with open(args.wire_json) as f: wire_json = json.loads(f.read()) + lpm_json = None + if args.lpm_json: + with open(args.lpm_json) as f: + lpm_json = json.loads(f.read()) + renders = [] params_dawn = parse_json(loaded_json, @@ -1025,12 +1035,53 @@ class MultiGeneratorFromDawnJSON(Generator): 'src/dawn/wire/server/ServerPrototypes_autogen.inc', wire_params)) + if 'dawn_lpmfuzz_proto' in targets: + params_dawn_wire = parse_json(loaded_json, + enabled_tags=['dawn', 'deprecated'], + disabled_tags=['native']) + additional_params = compute_wire_params(params_dawn_wire, + wire_json) + + lpm_params = [ + RENDER_PARAMS_BASE, params_dawn_wire, {}, additional_params + ] + + renders.append( + FileRender('dawn/fuzzers/lpmfuzz/dawn_lpm.proto', + 'src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto', + lpm_params)) + + if 'dawn_lpmfuzz_cpp' in targets: + params_dawn_wire = parse_json(loaded_json, + enabled_tags=['dawn', 'deprecated'], + disabled_tags=['native']) + additional_params = compute_wire_params(params_dawn_wire, + wire_json) + + lpm_params = [ + RENDER_PARAMS_BASE, params_dawn_wire, {}, additional_params + ] + + renders.append( + FileRender( + 'dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp', + 'src/dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.cpp', + lpm_params)) + + renders.append( + FileRender( + 'dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h', + 'src/dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.h', + lpm_params)) + return renders def get_dependencies(self, args): deps = [os.path.abspath(args.dawn_json)] if args.wire_json != None: deps += [os.path.abspath(args.wire_json)] + if args.lpm_json != None: + deps += [os.path.abspath(args.lpm_json)] return deps diff --git a/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp new file mode 100644 index 0000000000..76d8a7aee6 --- /dev/null +++ b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.cpp @@ -0,0 +1,50 @@ +// Copyright 2023 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 "dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.h" +#include "dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h" +#include "dawn/wire/Wire.h" +#include "dawn/wire/WireClient.h" +#include "dawn/wire/WireCmd_autogen.h" +#include "dawn/wire/client/ApiObjects_autogen.h" +#include "dawn/webgpu.h" +#include "dawn/wire/client/Client.h" + + +namespace dawn::wire { + +void SerializedData(const fuzzing::Program& program, dawn::wire::ChunkedCommandSerializer serializer) { + DawnLPMObjectIdProvider provider; + + for (const fuzzing::Command& command : program.commands()) { + switch (command.command_case()) { + + {% for command in cmd_records["command"] %} + case fuzzing::Command::k{{command.name.CamelCase()}}: { + {{ command.name.CamelCase() }}Cmd {{ 'cmd' }}; + // TODO(chromium:1374747): Populate command buffer with serialized code from generated + // protobuf structures. Currently, this will nullptr-deref constantly. + memset(&{{ 'cmd' }}, 0, sizeof({{ command.name.CamelCase() }}Cmd)); + serializer.SerializeCommand(cmd, provider); + break; + } + {% endfor %} + default: { + break; + } + } + } +} + +} // namespace dawn::wire diff --git a/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h new file mode 100644 index 0000000000..f5d0ef5982 --- /dev/null +++ b/generator/templates/dawn/fuzzers/lpmfuzz/DawnLPMSerializer.h @@ -0,0 +1,46 @@ +// Copyright 2023 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. + +#ifndef SRC_DAWN_FUZZERS_DAWNLPMSERIALIZER_H_ +#define SRC_DAWN_FUZZERS_DAWNLPMSERIALIZER_H_ + +#include "dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h" +#include "dawn/wire/ChunkedCommandSerializer.h" +#include "dawn/wire/WireCmd_autogen.h" + +namespace dawn::wire { + +class DawnLPMObjectIdProvider : public ObjectIdProvider { + private: + + // Implementation of the ObjectIdProvider interface + {% for type in by_category["object"] %} + WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const final { + *out = reinterpret_cast(object); + return WireResult::Success; + } + WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const final { + *out = reinterpret_cast(object); + return WireResult::Success; + } + {% endfor %} + +}; + +void SerializedData(const fuzzing::Program& program, + dawn::wire::ChunkedCommandSerializer serializer); + +} // namespace dawn::wire + +#endif // SRC_DAWN_FUZZERS_DAWNLPMSERIALIZER_H_ diff --git a/generator/templates/dawn/fuzzers/lpmfuzz/dawn_lpm.proto b/generator/templates/dawn/fuzzers/lpmfuzz/dawn_lpm.proto new file mode 100644 index 0000000000..3c30312d92 --- /dev/null +++ b/generator/templates/dawn/fuzzers/lpmfuzz/dawn_lpm.proto @@ -0,0 +1,32 @@ +// Copyright 2023 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. + +syntax = "proto2"; +package fuzzing; + +{% for command in cmd_records["command"] %} + message {{command.name.CamelCase()}} {} +{% endfor %} + +message Command { + oneof command { + {% for command in cmd_records["command"] %} + {{command.name.CamelCase()}} {{command.name.camelCase()}} = {{ loop.index }}; + {% endfor %} + } +} + +message Program { + repeated Command commands = 1; +} \ No newline at end of file diff --git a/src/dawn/fuzzers/BUILD.gn b/src/dawn/fuzzers/BUILD.gn index f7ea2a044d..875a11592c 100644 --- a/src/dawn/fuzzers/BUILD.gn +++ b/src/dawn/fuzzers/BUILD.gn @@ -12,9 +12,12 @@ # See the License for the specific language governing permissions and # limitations under the License. -import("//build_overrides/build.gni") import("../../../scripts/dawn_overrides_with_defaults.gni") +import("//build_overrides/build.gni") +import("${dawn_root}/scripts/dawn_features.gni") +import("${dawn_root}/src/dawn/fuzzers/dawn_fuzzers.gni") + # 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 @@ -110,6 +113,68 @@ dawn_fuzzer_test("dawn_wire_server_and_vulkan_backend_fuzzer") { additional_configs = [ "${dawn_root}/src/dawn/common:internal_config" ] } +if (is_dawn_lpm_fuzzer && build_with_chromium && dawn_use_swiftshader) { + import("//third_party/protobuf/proto_library.gni") + import("${dawn_root}/generator/dawn_generator.gni") + + dawn_json_lpm_generator("dawn_lpmfuzz_cpp") { + target = "dawn_lpmfuzz_cpp" + outputs = [ + "src/dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.cpp", + "src/dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.h", + ] + } + + dawn_json_lpm_generator("dawn_lpmfuzz_proto") { + target = "dawn_lpmfuzz_proto" + outputs = [ "src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto" ] + } + + proto_library("dawn_lpm_proto") { + proto_in_dir = "//" + sources = get_target_outputs(":dawn_lpmfuzz_proto") + + use_protobuf_full = true + deps = [ + ":dawn_lpmfuzz_proto", + "//third_party/protobuf:protobuf_full", + ] + } + + copy("copy_dawn_lpm_proto_outputs") { + # Hardcoded filenames because we can't get_target_outputs from a proto_library + # TODO(tiszka): crbug.com/1410213 + sources = [ + "$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.cc", + "$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h", + ] + outputs = [ "$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/{{source_file_part}}" ] + deps = [ ":dawn_lpm_proto" ] + } + + dawn_fuzzer_test("dawn_lpm_fuzzer_and_vulkan_backend") { + sources = get_target_outputs(":dawn_lpmfuzz_cpp") + sources += [ + "lpmfuzz/DawnLPMFuzzer.cpp", + "lpmfuzz/DawnLPMFuzzer.h", + "lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp", + ] + + deps = [ + ":copy_dawn_lpm_proto_outputs", + ":dawn_lpmfuzz_cpp", + "${dawn_root}/src/dawn:cpp", + "${dawn_root}/src/dawn:proc", + "${dawn_root}/src/dawn/common", + "${dawn_root}/src/dawn/native:static", + "${dawn_root}/src/dawn/utils", + "${dawn_root}/src/dawn/wire:static", + "//third_party/dawn/src/dawn/fuzzers:dawn_lpm_proto", + "//third_party/libprotobuf-mutator", + ] + } +} + # A group target to build all the fuzzers group("fuzzers") { testonly = true diff --git a/src/dawn/fuzzers/dawn_fuzzers.gni b/src/dawn/fuzzers/dawn_fuzzers.gni new file mode 100644 index 0000000000..d14d41750d --- /dev/null +++ b/src/dawn/fuzzers/dawn_fuzzers.gni @@ -0,0 +1,19 @@ +# Copyright 2023 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. + +# Build flag for dawn lpm fuzzers + +declare_args() { + is_dawn_lpm_fuzzer = false +} diff --git a/src/dawn/fuzzers/lpmfuzz/DawnLPMConstants.h b/src/dawn/fuzzers/lpmfuzz/DawnLPMConstants.h new file mode 100644 index 0000000000..2d173dab78 --- /dev/null +++ b/src/dawn/fuzzers/lpmfuzz/DawnLPMConstants.h @@ -0,0 +1,15 @@ +// Copyright 2023 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. + +#define INSTANCE_OBJECT_ID 1 diff --git a/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.cpp b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.cpp new file mode 100644 index 0000000000..3b7533dfad --- /dev/null +++ b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.cpp @@ -0,0 +1,133 @@ +// Copyright 2023 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 "dawn/common/Assert.h" +#include "dawn/common/Log.h" +#include "dawn/common/SystemUtils.h" +#include "dawn/dawn_proc.h" +#include "dawn/fuzzers/lpmfuzz/DawnLPMConstants.h" +#include "dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h" +#include "dawn/fuzzers/lpmfuzz/DawnLPMSerializer_autogen.h" +#include "dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h" +#include "dawn/native/DawnNative.h" +#include "dawn/utils/SystemUtils.h" +#include "dawn/utils/TerribleCommandBuffer.h" +#include "dawn/webgpu_cpp.h" +#include "dawn/wire/ChunkedCommandSerializer.h" +#include "dawn/wire/WireClient.h" +#include "dawn/wire/WireServer.h" +#include "testing/libfuzzer/libfuzzer_exports.h" + +namespace { + +class DevNull : public dawn::wire::CommandSerializer { + public: + size_t GetMaximumAllocationSize() const override { + // Some fuzzer bots have a 2GB allocation limit. Pick a value reasonably below that. + return 1024 * 1024 * 1024; + } + void* GetCmdSpace(size_t size) override { + if (size > buf.size()) { + buf.resize(size); + } + return buf.data(); + } + bool Flush() override { return true; } + + private: + std::vector buf; +}; + +std::unique_ptr sInstance; +WGPUProcDeviceCreateSwapChain sOriginalDeviceCreateSwapChain = nullptr; +static bool (*sAdapterSupported)(const dawn::native::Adapter&) = nullptr; + +WGPUSwapChain ErrorDeviceCreateSwapChain(WGPUDevice device, + WGPUSurface surface, + const WGPUSwapChainDescriptor*) { + WGPUSwapChainDescriptor desc = {}; + // A 0 implementation will trigger a swapchain creation error. + desc.implementation = 0; + return sOriginalDeviceCreateSwapChain(device, surface, &desc); +} + +} // namespace + +int DawnLPMFuzzer::Initialize(int* argc, char*** argv) { + // TODO(crbug.com/1038952): The Instance must be static because destructing the vkInstance with + // Swiftshader crashes libFuzzer. When this is fixed, move this into Run so that error injection + // for adapter discovery can be fuzzed. + sInstance = std::make_unique(); + sInstance->DiscoverDefaultAdapters(); + + return 0; +} + +int DawnLPMFuzzer::Run(const fuzzing::Program& program, + bool (*AdapterSupported)(const dawn::native::Adapter&)) { + sAdapterSupported = AdapterSupported; + + DawnProcTable procs = dawn::native::GetProcs(); + + // Swapchains receive a pointer to an implementation. The fuzzer will pass garbage in so we + // intercept calls to create swapchains and make sure they always return error swapchains. + // This is ok for fuzzing because embedders of dawn_wire would always define their own + // swapchain handling. + sOriginalDeviceCreateSwapChain = procs.deviceCreateSwapChain; + procs.deviceCreateSwapChain = ErrorDeviceCreateSwapChain; + + // Override requestAdapter to find an adapter that the fuzzer supports. + procs.instanceRequestAdapter = [](WGPUInstance cInstance, + const WGPURequestAdapterOptions* options, + WGPURequestAdapterCallback callback, void* userdata) { + std::vector adapters = sInstance->GetAdapters(); + for (dawn::native::Adapter adapter : adapters) { + if (sAdapterSupported(adapter)) { + WGPUAdapter cAdapter = adapter.Get(); + dawn::native::GetProcs().adapterReference(cAdapter); + callback(WGPURequestAdapterStatus_Success, cAdapter, nullptr, userdata); + return; + } + } + callback(WGPURequestAdapterStatus_Unavailable, nullptr, "No supported adapter.", userdata); + }; + + dawnProcSetProcs(&procs); + + DevNull devNull; + dawn::wire::WireServerDescriptor serverDesc = {}; + serverDesc.procs = &procs; + serverDesc.serializer = &devNull; + + std::unique_ptr wireServer(new dawn_wire::WireServer(serverDesc)); + wireServer->InjectInstance(sInstance->Get(), INSTANCE_OBJECT_ID, 0); + + static utils::TerribleCommandBuffer* mCommandBuffer = new utils::TerribleCommandBuffer(); + static dawn::wire::ChunkedCommandSerializer mSerializer = + dawn::wire::ChunkedCommandSerializer(mCommandBuffer); + mCommandBuffer->SetHandler(wireServer.get()); + + dawn::wire::SerializedData(program, mSerializer); + + mCommandBuffer->Flush(); + + // Note: Deleting the server will release all created objects. + // Deleted devices will wait for idle on destruction. + wireServer = nullptr; + return 0; +} diff --git a/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h new file mode 100644 index 0000000000..f0dcaee612 --- /dev/null +++ b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h @@ -0,0 +1,34 @@ +// Copyright 2023 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. + +#ifndef SRC_DAWN_FUZZERS_DAWNLPMFUZZER_H_ +#define SRC_DAWN_FUZZERS_DAWNLPMFUZZER_H_ + +#include "dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h" +#include "dawn/webgpu_cpp.h" + +namespace dawn::native { + +class Adapter; + +} // namespace dawn::native + +namespace DawnLPMFuzzer { + +int Initialize(int* argc, char*** argv); + +int Run(const fuzzing::Program& program, bool (*AdapterSupported)(const dawn::native::Adapter&)); +} // namespace DawnLPMFuzzer + +#endif // SRC_DAWN_FUZZERS_DAWNLPMFUZZER_H_ diff --git a/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp new file mode 100644 index 0000000000..d25e0a1857 --- /dev/null +++ b/src/dawn/fuzzers/lpmfuzz/DawnLPMFuzzerAndVulkanBackend.cpp @@ -0,0 +1,33 @@ +// Copyright 2023 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 "dawn/common/GPUInfo.h" +#include "dawn/fuzzers/lpmfuzz/DawnLPMFuzzer.h" +#include "dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h" +#include "dawn/native/DawnNative.h" +#include "testing/libfuzzer/libfuzzer_exports.h" +#include "testing/libfuzzer/proto/lpm_interface.h" + +extern "C" int LLVMFuzzerInitialize(int* argc, char*** argv) { + return DawnLPMFuzzer::Initialize(argc, argv); +} + +DEFINE_PROTO_FUZZER(const fuzzing::Program& program) { + DawnLPMFuzzer::Run(program, [](const dawn::native::Adapter& adapter) { + wgpu::AdapterProperties properties; + adapter.GetProperties(&properties); + + return gpu_info::IsGoogleSwiftshader(properties.vendorID, properties.deviceID); + }); +} diff --git a/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json b/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json new file mode 100644 index 0000000000..992426c15b --- /dev/null +++ b/src/dawn/fuzzers/lpmfuzz/dawn_lpm.json @@ -0,0 +1,19 @@ +{ + "_comment": [ + "Copyright 2023 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." + ], + + "_doc": "See docs/dawn/codegen.md" +} \ No newline at end of file