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 <cwallez@chromium.org>
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brendon Tiszka <tiszka@chromium.org>
diff --git a/docs/dawn/codegen.md b/docs/dawn/codegen.md
index 1bded3f..359fdde 100644
--- a/docs/dawn/codegen.md
+++ b/docs/dawn/codegen.md
@@ -111,3 +111,12 @@
## 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 9b6183f..6a4e090 100644
--- a/generator/dawn_generator.gni
+++ b/generator/dawn_generator.gni
@@ -80,3 +80,25 @@
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 e818d2a..8eb0d6c 100644
--- a/generator/dawn_json_generator.py
+++ b/generator/dawn_json_generator.py
@@ -777,7 +777,7 @@
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 @@
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 @@
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 @@
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 @@
'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 0000000..76d8a7a
--- /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 0000000..f5d0ef5
--- /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<uintptr_t>(object);
+ return WireResult::Success;
+ }
+ WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const final {
+ *out = reinterpret_cast<uintptr_t>(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 0000000..3c30312
--- /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 f7ea2a0..875a115 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 @@
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 0000000..d14d417
--- /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 0000000..2d173da
--- /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 0000000..3b7533d
--- /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 <fstream>
+#include <memory>
+#include <vector>
+
+#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<char> buf;
+};
+
+std::unique_ptr<dawn::native::Instance> 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<dawn::native::Instance>();
+ 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<dawn::native::Adapter> 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<dawn::wire::WireServer> 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 0000000..f0dcaee
--- /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 0000000..d25e0a1
--- /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 0000000..992426c
--- /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