// 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_custom_lpm.proto"; // These are hardcoded limits for Dawn Object allocations based on type to help // guide the fuzzer towards reusing existing objects. {% for type in by_category["object"] %} {% set type_key = type.name.canonical_case() %} enum {{ type.name.CamelCase() }}Id { {% if type_key in cmd_records["lpm_info"]["limits"] %} {% for n in range(cmd_records["lpm_info"]["limits"][type_key]) %} {{ type.name.SNAKE_CASE() }}_{{ loop.index }} = {{ loop.index }}; {% endfor %} {% else %} {% for n in range(cmd_records["lpm_info"]["limits"]["default"]) %} {{ type.name.SNAKE_CASE() }}_{{ loop.index }} = {{ loop.index }}; {% endfor %} {% endif %} INVALID_{{ type.name.SNAKE_CASE() }} = {{ cmd_records["lpm_info"]["invalid object id"] }}; }; {% endfor %} {% for type in by_category["enum"] %} enum {{as_cppType(type.name)}} { {% for value in type.values %} {{ as_cppType(type.name) }}{{as_cppEnum(value.name)}} = {{ value.value }}; {% endfor %} }; {% endfor %} {% for type in by_category["bitmask"] %} enum {{as_cppType(type.name)}} { {% for value in type.values %} {{ as_cppType(type.name) }}{{as_cppEnum(value.name)}} = {{ value.value }}; {% endfor %} }; {% endfor %} {% macro lift_string_proto_member(member, count) -%} required string {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {%- endmacro %} {% macro lift_float_array_proto_member(member, count) -%} repeated float {{ as_varName(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {%- endmacro %} {% macro lift_object_member(member, count) %} {{ member.type.name.CamelCase() }}Id {{ as_protobufNameLPM(member.name) }} {% endmacro %} {% macro lift_objectid_member(member, count) %} {{ member.id_type.name.CamelCase() }}Id {{ as_protobufNameLPM(member.name) }} {% endmacro %} {% macro lift_varlength_proto_member(member, count) -%} {% if member.type in by_category["object"] %} repeated {{ lift_object_member(member, count) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type.name.get() == "object id" %} repeated {{ lift_objectid_member(member, count) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% else %} repeated {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% endif %} {%- endmacro %} {% macro lift_dawn_member_pass_by_value(record, name, member, count) %} {% if member.type in by_category["structure"] %} required {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type in by_category["bitmask"] %} repeated {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type in by_category["enum"] %} required {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type in by_category["object"] %} required {{ lift_object_member(member, count) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type.name.get() == "ObjectId" %} required {{ lift_objectid_member(member, count) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type.name.get() == "ObjectHandle" %} // Skips object handles while lifting dawn.json to protobuf because // ObjectHandles are created and managed in DawnLPMSerializer. Passing // arbitrary ObjectHandles from the fuzzer's bytestream isn't the // strategy for this fuzzer. {% else %} required {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% endif %} {% endmacro %} {% macro lift_dawn_member_pass_by_pointer(record, name, member, count) %} {% if member.type in by_category["structure"] and member.length == "constant" and member.constant_length == 1 %} required {{ as_protobufTypeLPM(member) }} {{ as_protobufNameLPM(member.name) }} = {{ count.value }}; {% set count.value = count.value + 1 %} {% elif member.type.name.get() == "char" and member.length == 'strlen' %} {{ lift_string_proto_member(member, count) }} {% elif member.type.name.get() == "float" %} {{ lift_float_array_proto_member(member, count) }} {% elif member.type.name.get() == "uint8_t" %} // Skip over byte arrays in protobuf, handled by DawnLPMSerializer // with a hardcoded bytes and length. {% elif member.length != 'constant' %} {{ lift_varlength_proto_member(member, count) }} {% else %} // There shouldn't be any other pass-by-pointer types in // dawn*.json, if any are added we would like to know at compile time {{ unreachable_code() }} {% endif %} {% endmacro %} {% macro lift_proto_members_helper(record, name, members) %} {% set count = namespace(value=1) %} {% for member in members %} {% if member.skip_serialize == True %} // {{ member.name.camelCase()}}.skip_serialize {% elif member.annotation == 'value' %} {{ lift_dawn_member_pass_by_value(record, name, member, count) }} {% elif member.annotation == 'const*' %} {{ lift_dawn_member_pass_by_pointer(record, name, member, count) }} {% endif %} {% endfor %} {% endmacro %} {% for structure in by_category["structure"] %} message {{structure.name.CamelCase()}} { {{ lift_proto_members_helper(structure, structure.name, structure.members) }} } {% 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 { oneof command { {% for command in cmd_records["proto_all_commands"] %} {{command.name.CamelCase()}} {{command.name.camelCase()}} = {{ loop.index }}; {% endfor %} } } message Program { repeated Command commands = 1; }