Add Dawn Wire Server LPM Fuzzer [3/N]

Add ability to define custom protobuf structures for commands that
need to be hand written.

Bug: chromium:1374747
Change-Id: I69d5c55d69c3544835a23e4e0360900b991ccbd3
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/114643
Kokoro: Kokoro <noreply+kokoro@google.com>
Reviewed-by: Austin Eng <enga@chromium.org>
Commit-Queue: Brendon Tiszka <tiszka@chromium.org>
This commit is contained in:
Brendon Tiszka 2023-05-02 21:41:22 +00:00 committed by Dawn LUCI CQ
parent ebafab6556
commit 1f8413f50a
8 changed files with 106 additions and 48 deletions

View File

@ -580,12 +580,12 @@ def compute_lpm_params(api_and_wire_params, lpm_json):
# Start with all commands in dawn.json and dawn_wire.json # Start with all commands in dawn.json and dawn_wire.json
lpm_params = api_and_wire_params.copy() lpm_params = api_and_wire_params.copy()
# Commands that are built through generation # Commands that are built through codegen
proto_generated_commands = [] generated_commands = []
# All commands, including hand written commands that we can't generate # All commands, including hand written commands that we can't generate
# through codegen # through codegen
proto_all_commands = [] all_commands = []
# Remove blocklisted commands from protobuf generation params # Remove blocklisted commands from protobuf generation params
blocklisted_cmds_proto = lpm_json.get('blocklisted_cmds') blocklisted_cmds_proto = lpm_json.get('blocklisted_cmds')
@ -594,13 +594,17 @@ def compute_lpm_params(api_and_wire_params, lpm_json):
blocklisted = command.name.get() in blocklisted_cmds_proto blocklisted = command.name.get() in blocklisted_cmds_proto
custom = command.name.get() in custom_cmds_proto custom = command.name.get() in custom_cmds_proto
if not blocklisted and not custom: if blocklisted:
proto_generated_commands.append(command) continue
proto_all_commands.append(command)
if not custom:
generated_commands.append(command)
all_commands.append(command)
lpm_params['cmd_records'] = { lpm_params['cmd_records'] = {
'proto_generated_commands': proto_generated_commands, 'proto_generated_commands': generated_commands,
'proto_all_commands': proto_all_commands, 'proto_all_commands': all_commands,
'cpp_generated_commands': generated_commands
} }
return lpm_params return lpm_params
@ -1132,6 +1136,12 @@ class MultiGeneratorFromDawnJSON(Generator):
'src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto', 'src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto',
lpm_params)) lpm_params))
renders.append(
FileRender(
'dawn/fuzzers/lpmfuzz/dawn_object_types_lpm.proto',
'src/dawn/fuzzers/lpmfuzz/dawn_object_types_lpm_autogen.proto',
lpm_params))
if 'dawn_lpmfuzz_cpp' in targets: if 'dawn_lpmfuzz_cpp' in targets:
params_dawn_wire = parse_json(loaded_json, params_dawn_wire = parse_json(loaded_json,
enabled_tags=['dawn', 'deprecated'], enabled_tags=['dawn', 'deprecated'],
@ -1139,8 +1149,11 @@ class MultiGeneratorFromDawnJSON(Generator):
api_and_wire_params = compute_wire_params(params_dawn_wire, api_and_wire_params = compute_wire_params(params_dawn_wire,
wire_json) wire_json)
fuzzer_params = compute_lpm_params(api_and_wire_params, lpm_json)
lpm_params = [ lpm_params = [
RENDER_PARAMS_BASE, params_dawn_wire, {}, api_and_wire_params RENDER_PARAMS_BASE, params_dawn_wire, {}, api_and_wire_params,
fuzzer_params
] ]
renders.append( renders.append(

View File

@ -30,7 +30,7 @@ void SerializedData(const fuzzing::Program& program, dawn::wire::ChunkedCommandS
for (const fuzzing::Command& command : program.commands()) { for (const fuzzing::Command& command : program.commands()) {
switch (command.command_case()) { switch (command.command_case()) {
{% for command in cmd_records["command"] %} {% for command in cmd_records["cpp_generated_commands"] %}
case fuzzing::Command::k{{command.name.CamelCase()}}: { case fuzzing::Command::k{{command.name.CamelCase()}}: {
{{ command.name.CamelCase() }}Cmd {{ 'cmd' }}; {{ command.name.CamelCase() }}Cmd {{ 'cmd' }};
// TODO(chromium:1374747): Populate command buffer with serialized code from generated // TODO(chromium:1374747): Populate command buffer with serialized code from generated

View File

@ -15,6 +15,7 @@
syntax = "proto2"; syntax = "proto2";
package fuzzing; package fuzzing;
import "third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_custom_lpm.proto";
{% for type in by_category["enum"] %} {% for type in by_category["enum"] %}
enum {{as_cppType(type.name)}} { enum {{as_cppType(type.name)}} {
@ -129,16 +130,12 @@ package fuzzing;
{% endfor %} {% endfor %}
{% for command in cmd_records["proto_all_commands"] %}
{% if command not in cmd_records["proto_generated_commands"] %}
message {{command.name.CamelCase()}} {}
{% else %}
message {{command.name.CamelCase()}} {
{{ lift_proto_members_helper(command, command.name, command.members) }}
}
{% endif %}
{% endfor %}
{% for command in cmd_records["proto_generated_commands"] %}
message {{command.name.CamelCase()}} {
{{ lift_proto_members_helper(command, command.name, command.members) }}
}
{% endfor %}
message Command { message Command {
oneof command { oneof command {

View File

@ -0,0 +1,22 @@
// 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;
enum ObjectType {
{% for type in by_category["object"] %}
{{ type.name.CamelCase() }} = {{ loop.index - 1}};
{% endfor %}
};

View File

@ -128,26 +128,42 @@ if (is_dawn_lpm_fuzzer && build_with_chromium && dawn_use_swiftshader) {
dawn_json_lpm_generator("dawn_lpmfuzz_proto") { dawn_json_lpm_generator("dawn_lpmfuzz_proto") {
target = "dawn_lpmfuzz_proto" target = "dawn_lpmfuzz_proto"
outputs = [ "src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto" ] outputs = [
"src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.proto",
"src/dawn/fuzzers/lpmfuzz/dawn_object_types_lpm_autogen.proto",
]
}
copy("copy_dawn_custom_lpms") {
# Hardcoded paths because we can't get_target_outputs from a proto_library
# TODO(tiszka): crbug.com/1410213
sources = [ "${dawn_root}/src/dawn/fuzzers/lpmfuzz/dawn_custom_lpm.proto" ]
outputs = [ "$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_custom_lpm.proto" ]
} }
proto_library("dawn_lpm_proto") { proto_library("dawn_lpm_proto") {
proto_in_dir = "//" proto_in_dir = "$root_out_dir/gen"
sources = get_target_outputs(":dawn_lpmfuzz_proto") sources = get_target_outputs(":dawn_lpmfuzz_proto")
sources += get_target_outputs(":copy_dawn_custom_lpms")
use_protobuf_full = true use_protobuf_full = true
deps = [ deps = [
":copy_dawn_custom_lpms",
":dawn_lpmfuzz_proto", ":dawn_lpmfuzz_proto",
"//third_party/protobuf:protobuf_full", "//third_party/protobuf:protobuf_full",
] ]
} }
copy("copy_dawn_lpm_proto_outputs") { copy("copy_dawn_lpm_proto_outputs") {
# Hardcoded filenames because we can't get_target_outputs from a proto_library # Hardcoded paths because we can't get_target_outputs from a proto_library
# TODO(tiszka): crbug.com/1410213 # TODO(tiszka): crbug.com/1410213
sources = [ sources = [
"$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_custom_lpm.pb.cc",
"$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_custom_lpm.pb.h",
"$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.cc",
"$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h", "$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_lpm_autogen.pb.h",
"$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_object_types_lpm_autogen.pb.cc",
"$root_out_dir/gen/$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_object_types_lpm_autogen.pb.h",
] ]
outputs = [ "$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/{{source_file_part}}" ] outputs = [ "$root_out_dir/gen/third_party/dawn/src/dawn/fuzzers/lpmfuzz/{{source_file_part}}" ]
deps = [ ":dawn_lpm_proto" ] deps = [ ":dawn_lpm_proto" ]

View File

@ -54,18 +54,8 @@ class DevNull : public dawn::wire::CommandSerializer {
}; };
std::unique_ptr<dawn::native::Instance> sInstance; std::unique_ptr<dawn::native::Instance> sInstance;
WGPUProcDeviceCreateSwapChain sOriginalDeviceCreateSwapChain = nullptr;
static bool (*sAdapterSupported)(const dawn::native::Adapter&) = 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 } // namespace
namespace DawnLPMFuzzer { namespace DawnLPMFuzzer {
@ -85,13 +75,6 @@ int Run(const fuzzing::Program& program, bool (*AdapterSupported)(const dawn::na
DawnProcTable procs = dawn::native::GetProcs(); 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. // Override requestAdapter to find an adapter that the fuzzer supports.
procs.instanceRequestAdapter = [](WGPUInstance cInstance, procs.instanceRequestAdapter = [](WGPUInstance cInstance,
const WGPURequestAdapterOptions* options, const WGPURequestAdapterOptions* options,

View File

@ -0,0 +1,27 @@
// 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;
import "third_party/dawn/src/dawn/fuzzers/lpmfuzz/dawn_object_types_lpm_autogen.proto";
message DeviceCreateShaderModule {
required uint32 self = 1;
}
message DestroyObject {
required ObjectType objectType = 1;
required uint32 objectId = 2;
}

View File

@ -17,16 +17,16 @@
"_doc": "See docs/dawn/codegen.md", "_doc": "See docs/dawn/codegen.md",
"custom_cmds": [], "custom_cmds": [
"blocklisted_cmds": [
"surface descriptor from windows core window",
"surface descriptor from windows swap chain panel",
"surface descriptor from canvas html selector",
"device create render pipeline",
"device create render pipeline async",
"device create shader module", "device create shader module",
"destroy object" "destroy object"
] ],
"blocklisted_cmds": [
"device create render pipeline",
"device create render pipeline async",
"surface descriptor from windows core window",
"surface descriptor from windows swap chain panel",
"surface descriptor from canvas html selector"
]
} }