• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //* Copyright 2017 The Dawn Authors
2 //*
3 //* Licensed under the Apache License, Version 2.0 (the "License");
4 //* you may not use this file except in compliance with the License.
5 //* You may obtain a copy of the License at
6 //*
7 //*     http://www.apache.org/licenses/LICENSE-2.0
8 //*
9 //* Unless required by applicable law or agreed to in writing, software
10 //* distributed under the License is distributed on an "AS IS" BASIS,
11 //* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 //* See the License for the specific language governing permissions and
13 //* limitations under the License.
14 
15 #include "dawn_wire/WireCmd_autogen.h"
16 
17 #include "common/Assert.h"
18 #include "common/Log.h"
19 #include "dawn_wire/BufferConsumer_impl.h"
20 #include "dawn_wire/Wire.h"
21 
22 #include <algorithm>
23 #include <cstring>
24 #include <limits>
25 
26 #ifdef __GNUC__
27 // error: 'offsetof' within non-standard-layout type 'wgpu::XXX' is conditionally-supported
28 #pragma GCC diagnostic ignored "-Winvalid-offsetof"
29 #endif
30 
31 //* Helper macros so that the main [de]serialization functions can be written in a generic manner.
32 
33 //* Outputs an rvalue that's the number of elements a pointer member points to.
34 {% macro member_length(member, record_accessor) -%}
35     {%- if member.length == "constant" -%}
36         {{member.constant_length}}u
37     {%- else -%}
38         {{record_accessor}}{{as_varName(member.length.name)}}
39     {%- endif -%}
40 {%- endmacro %}
41 
42 //* Outputs the type that will be used on the wire for the member
43 {% macro member_transfer_type(member) -%}
44     {%- if member.type.category == "object" -%}
45         ObjectId
46     {%- elif member.type.category == "structure" -%}
47         {{as_cType(member.type.name)}}Transfer
48     {%- elif member.type.category == "bitmask" -%}
49         {{as_cType(member.type.name)}}Flags
50     {%- else -%}
51         {{ assert(as_cType(member.type.name) != "size_t") }}
52         {{as_cType(member.type.name)}}
53     {%- endif -%}
54 {%- endmacro %}
55 
56 //* Outputs the size of one element of the type that will be used on the wire for the member
57 {% macro member_transfer_sizeof(member) -%}
58     sizeof({{member_transfer_type(member)}})
59 {%- endmacro %}
60 
61 //* Outputs the serialization code to put `in` in `out`
62 {% macro serialize_member(member, in, out) %}
63     {%- if member.type.category == "object" -%}
64         {%- set Optional = "Optional" if member.optional else "" -%}
65         WIRE_TRY(provider.Get{{Optional}}Id({{in}}, &{{out}}));
66     {% elif member.type.category == "structure"%}
67         {%- set Provider = ", provider" if member.type.may_have_dawn_object else "" -%}
68         WIRE_TRY({{as_cType(member.type.name)}}Serialize({{in}}, &{{out}}, buffer{{Provider}}));
69     {%- else -%}
70         {{out}} = {{in}};
71     {%- endif -%}
72 {% endmacro %}
73 
74 //* Outputs the deserialization code to put `in` in `out`
75 {% macro deserialize_member(member, in, out) %}
76     {%- if member.type.category == "object" -%}
77         {%- set Optional = "Optional" if member.optional else "" -%}
78         WIRE_TRY(resolver.Get{{Optional}}FromId({{in}}, &{{out}}));
79     {%- elif member.type.category == "structure" -%}
80         WIRE_TRY({{as_cType(member.type.name)}}Deserialize(&{{out}}, &{{in}}, deserializeBuffer, allocator
81             {%- if member.type.may_have_dawn_object -%}
82                 , resolver
83             {%- endif -%}
84         ));
85     {%- else -%}
86         static_assert(sizeof({{out}}) >= sizeof({{in}}), "Deserialize assignment may not narrow.");
87         {{out}} = {{in}};
88     {%- endif -%}
89 {% endmacro %}
90 
91 //* The main [de]serialization macro
92 //* Methods are very similar to structures that have one member corresponding to each arguments.
93 //* This macro takes advantage of the similarity to output [de]serialization code for a record
94 //* that is either a structure or a method, with some special cases for each.
95 {% macro write_record_serialization_helpers(record, name, members, is_cmd=False, is_return_command=False) %}
96     {% set Return = "Return" if is_return_command else "" %}
97     {% set Cmd = "Cmd" if is_cmd else "" %}
98     {% set Inherits = " : CmdHeader" if is_cmd else "" %}
99 
100     //* Structure for the wire format of each of the records. Members that are values
101     //* are embedded directly in the structure. Other members are assumed to be in the
102     //* memory directly following the structure in the buffer.
103     struct {{Return}}{{name}}Transfer{{Inherits}} {
104         static_assert({{[is_cmd, record.extensible, record.chained].count(True)}} <= 1,
105                       "Record must be at most one of is_cmd, extensible, and chained.");
106         {% if is_cmd %}
107             //* Start the transfer structure with the command ID, so that casting to WireCmd gives the ID.
108             {{Return}}WireCmd commandId;
109         {% elif record.extensible %}
110             bool hasNextInChain;
111         {% elif record.chained %}
112             WGPUChainedStructTransfer chain;
113         {% endif %}
114 
115         //* Value types are directly in the command, objects being replaced with their IDs.
116         {% for member in members if member.annotation == "value" %}
117             {{member_transfer_type(member)}} {{as_varName(member.name)}};
118         {% endfor %}
119 
120         //* const char* have their length embedded directly in the command.
121         {% for member in members if member.length == "strlen" %}
122             uint64_t {{as_varName(member.name)}}Strlen;
123         {% endfor %}
124 
125         {% for member in members if member.optional and member.annotation != "value" and member.type.category != "object" %}
126             bool has_{{as_varName(member.name)}};
127         {% endfor %}
128     };
129 
130     {% if is_cmd %}
131         static_assert(offsetof({{Return}}{{name}}Transfer, commandSize) == 0, "");
132         static_assert(offsetof({{Return}}{{name}}Transfer, commandId) == sizeof(CmdHeader), "");
133     {% endif %}
134 
135     {% if record.chained %}
136         static_assert(offsetof({{Return}}{{name}}Transfer, chain) == 0, "");
137     {% endif %}
138 
139     //* Returns the required transfer size for `record` in addition to the transfer structure.
140     DAWN_DECLARE_UNUSED size_t {{Return}}{{name}}GetExtraRequiredSize(const {{Return}}{{name}}{{Cmd}}& record) {
141         DAWN_UNUSED(record);
142 
143         size_t result = 0;
144 
145         //* Gather how much space will be needed for the extension chain.
146         {% if record.extensible %}
147             if (record.nextInChain != nullptr) {
148                 result += GetChainedStructExtraRequiredSize(record.nextInChain);
149             }
150         {% endif %}
151 
152         //* Special handling of const char* that have their length embedded directly in the command
153         {% for member in members if member.length == "strlen" %}
154             {% set memberName = as_varName(member.name) %}
155 
156             {% if member.optional %}
157                 bool has_{{memberName}} = record.{{memberName}} != nullptr;
158                 if (has_{{memberName}})
159             {% endif %}
160             {
161             result += std::strlen(record.{{memberName}});
162             }
163         {% endfor %}
164 
165         //* Gather how much space will be needed for pointer members.
166         {% for member in members if member.length != "strlen" and not member.skip_serialize %}
167             {% if member.type.category != "object" and member.optional %}
168                 if (record.{{as_varName(member.name)}} != nullptr)
169             {% endif %}
170             {
171                 {% if member.annotation != "value" %}
172                     auto memberLength = {{member_length(member, "record.")}};
173                     result += memberLength * {{member_transfer_sizeof(member)}};
174                     //* Structures might contain more pointers so we need to add their extra size as well.
175                     {% if member.type.category == "structure" %}
176                         for (decltype(memberLength) i = 0; i < memberLength; ++i) {
177                             {{assert(member.annotation == "const*")}}
178                             result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}}[i]);
179                         }
180                     {% endif %}
181                 {% elif member.type.category == "structure" %}
182                     result += {{as_cType(member.type.name)}}GetExtraRequiredSize(record.{{as_varName(member.name)}});
183                 {% endif %}
184             }
185         {% endfor %}
186 
187         return result;
188     }
189     // GetExtraRequiredSize isn't used for structures that are value members of other structures
190     // because we assume they cannot contain pointers themselves.
191     DAWN_UNUSED_FUNC({{Return}}{{name}}GetExtraRequiredSize);
192 
193     //* Serializes `record` into `transfer`, using `buffer` to get more space for pointed-to data
194     //* and `provider` to serialize objects.
195     DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Serialize(
196         const {{Return}}{{name}}{{Cmd}}& record,
197         {{Return}}{{name}}Transfer* transfer,
198         SerializeBuffer* buffer
199         {%- if record.may_have_dawn_object -%}
200             , const ObjectIdProvider& provider
201         {%- endif -%}
202     ) {
203         DAWN_UNUSED(buffer);
204 
205         //* Handle special transfer members of methods.
206         {% if is_cmd %}
207             transfer->commandId = {{Return}}WireCmd::{{name}};
208         {% endif %}
209 
210         //* Value types are directly in the transfer record, objects being replaced with their IDs.
211         {% for member in members if member.annotation == "value" %}
212             {% set memberName = as_varName(member.name) %}
213             {{serialize_member(member, "record." + memberName, "transfer->" + memberName)}}
214         {% endfor %}
215 
216         {% if record.extensible %}
217             if (record.nextInChain != nullptr) {
218                 transfer->hasNextInChain = true;
219                 WIRE_TRY(SerializeChainedStruct(record.nextInChain, buffer, provider));
220             } else {
221                 transfer->hasNextInChain = false;
222             }
223         {% endif %}
224 
225         {% if record.chained %}
226             //* Should be set by the root descriptor's call to SerializeChainedStruct.
227             ASSERT(transfer->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
228             ASSERT(transfer->chain.hasNext == (record.chain.next != nullptr));
229         {% endif %}
230 
231         //* Special handling of const char* that have their length embedded directly in the command
232         {% for member in members if member.length == "strlen" %}
233             {% set memberName = as_varName(member.name) %}
234 
235             {% if member.optional %}
236                 bool has_{{memberName}} = record.{{memberName}} != nullptr;
237                 transfer->has_{{memberName}} = has_{{memberName}};
238                 if (has_{{memberName}})
239             {% endif %}
240             {
241                 transfer->{{memberName}}Strlen = std::strlen(record.{{memberName}});
242 
243                 char* stringInBuffer;
244                 WIRE_TRY(buffer->NextN(transfer->{{memberName}}Strlen, &stringInBuffer));
245                 memcpy(stringInBuffer, record.{{memberName}}, transfer->{{memberName}}Strlen);
246             }
247         {% endfor %}
248 
249         //* Allocate space and write the non-value arguments in it.
250         {% for member in members if member.annotation != "value" and member.length != "strlen" and not member.skip_serialize %}
251             {% set memberName = as_varName(member.name) %}
252 
253             {% if member.type.category != "object" and member.optional %}
254                 bool has_{{memberName}} = record.{{memberName}} != nullptr;
255                 transfer->has_{{memberName}} = has_{{memberName}};
256                 if (has_{{memberName}})
257             {% endif %}
258             {
259                 auto memberLength = {{member_length(member, "record.")}};
260 
261                 {{member_transfer_type(member)}}* memberBuffer;
262                 WIRE_TRY(buffer->NextN(memberLength, &memberBuffer));
263 
264                 {% if member.type.is_wire_transparent %}
265                     memcpy(
266                         memberBuffer, record.{{memberName}},
267                         {{member_transfer_sizeof(member)}} * memberLength);
268                 {% else %}
269                     //* This loop cannot overflow because it iterates up to |memberLength|. Even if
270                     //* memberLength were the maximum integer value, |i| would become equal to it
271                     //* just before exiting the loop, but not increment past or wrap around.
272                     for (decltype(memberLength) i = 0; i < memberLength; ++i) {
273                         {{serialize_member(member, "record." + memberName + "[i]", "memberBuffer[i]" )}}
274                     }
275                 {% endif %}
276             }
277         {% endfor %}
278         return WireResult::Success;
279     }
280     DAWN_UNUSED_FUNC({{Return}}{{name}}Serialize);
281 
282     //* Deserializes `transfer` into `record` getting more serialized data from `buffer` and `size`
283     //* if needed, using `allocator` to store pointed-to values and `resolver` to translate object
284     //* Ids to actual objects.
285     DAWN_DECLARE_UNUSED WireResult {{Return}}{{name}}Deserialize(
286         {{Return}}{{name}}{{Cmd}}* record,
287         const volatile {{Return}}{{name}}Transfer* transfer,
288         DeserializeBuffer* deserializeBuffer,
289         DeserializeAllocator* allocator
290         {%- if record.may_have_dawn_object -%}
291             , const ObjectIdResolver& resolver
292         {%- endif -%}
293     ) {
294         DAWN_UNUSED(allocator);
295 
296         {% if is_cmd %}
297             ASSERT(transfer->commandId == {{Return}}WireCmd::{{name}});
298         {% endif %}
299 
300         {% if record.derived_method %}
301             record->selfId = transfer->self;
302         {% endif %}
303 
304         //* Value types are directly in the transfer record, objects being replaced with their IDs.
305         {% for member in members if member.annotation == "value" %}
306             {% set memberName = as_varName(member.name) %}
307             {{deserialize_member(member, "transfer->" + memberName, "record->" + memberName)}}
308         {% endfor %}
309 
310         {% if record.extensible %}
311             record->nextInChain = nullptr;
312             if (transfer->hasNextInChain) {
313                 WIRE_TRY(DeserializeChainedStruct(&record->nextInChain, deserializeBuffer, allocator, resolver));
314             }
315         {% endif %}
316 
317         {% if record.chained %}
318             //* Should be set by the root descriptor's call to DeserializeChainedStruct.
319             //* Don't check |record->chain.next| matches because it is not set until the
320             //* next iteration inside DeserializeChainedStruct.
321             ASSERT(record->chain.sType == {{as_cEnum(types["s type"].name, record.name)}});
322             ASSERT(record->chain.next == nullptr);
323         {% endif %}
324 
325         //* Special handling of const char* that have their length embedded directly in the command
326         {% for member in members if member.length == "strlen" %}
327             {% set memberName = as_varName(member.name) %}
328 
329             {% if member.optional %}
330                 bool has_{{memberName}} = transfer->has_{{memberName}};
331                 record->{{memberName}} = nullptr;
332                 if (has_{{memberName}})
333             {% endif %}
334             {
335                 uint64_t stringLength64 = transfer->{{memberName}}Strlen;
336                 if (stringLength64 >= std::numeric_limits<size_t>::max()) {
337                     //* Cannot allocate space for the string. It can be at most
338                     //* size_t::max() - 1. We need 1 byte for the null-terminator.
339                     return WireResult::FatalError;
340                 }
341                 size_t stringLength = static_cast<size_t>(stringLength64);
342 
343                 const volatile char* stringInBuffer;
344                 WIRE_TRY(deserializeBuffer->ReadN(stringLength, &stringInBuffer));
345 
346                 char* copiedString;
347                 WIRE_TRY(GetSpace(allocator, stringLength + 1, &copiedString));
348                 //* We can cast away the volatile qualifier because DeserializeBuffer::ReadN already
349                 //* validated that the range [stringInBuffer, stringInBuffer + stringLength) is valid.
350                 //* memcpy may have an unknown access pattern, but this is fine since the string is only
351                 //* data and won't affect control flow of this function.
352                 memcpy(copiedString, const_cast<const char*>(stringInBuffer), stringLength);
353                 copiedString[stringLength] = '\0';
354                 record->{{memberName}} = copiedString;
355             }
356         {% endfor %}
357 
358         //* Get extra buffer data, and copy pointed to values in extra allocated space.
359         {% for member in members if member.annotation != "value" and member.length != "strlen" %}
360             {% set memberName = as_varName(member.name) %}
361 
362             {% if member.type.category != "object" and member.optional %}
363                 //* Non-constant length optional members use length=0 to denote they aren't present.
364                 //* Otherwise we could have length=N and has_member=false, causing reads from an
365                 //* uninitialized pointer.
366                 {{ assert(member.length == "constant") }}
367                 bool has_{{memberName}} = transfer->has_{{memberName}};
368                 record->{{memberName}} = nullptr;
369                 if (has_{{memberName}})
370             {% endif %}
371             {
372                 auto memberLength = {{member_length(member, "record->")}};
373                 const volatile {{member_transfer_type(member)}}* memberBuffer;
374                 WIRE_TRY(deserializeBuffer->ReadN(memberLength, &memberBuffer));
375 
376                 //* For data-only members (e.g. "data" in WriteBuffer and WriteTexture), they are
377                 //* not security sensitive so we can directly refer the data inside the transfer
378                 //* buffer in dawn_native. For other members, as prevention of TOCTOU attacks is an
379                 //* important feature of the wire, we must make sure every single value returned to
380                 //* dawn_native must be a copy of what's in the wire.
381                 {% if member.json_data["wire_is_data_only"] %}
382                     record->{{memberName}} =
383                         const_cast<const {{member_transfer_type(member)}}*>(memberBuffer);
384 
385                 {% else %}
386                     {{as_cType(member.type.name)}}* copiedMembers;
387                     WIRE_TRY(GetSpace(allocator, memberLength, &copiedMembers));
388                     record->{{memberName}} = copiedMembers;
389 
390                     {% if member.type.is_wire_transparent %}
391                         //* memcpy is not allowed to copy from volatile objects. However, these
392                         //* arrays are just used as plain data, and don't impact control flow. So if
393                         //* the underlying data were changed while the copy was still executing, we
394                         //* would get different data - but it wouldn't cause unexpected downstream
395                         //* effects.
396                         memcpy(
397                             copiedMembers,
398                             const_cast<const {{member_transfer_type(member)}}*>(memberBuffer),
399                            {{member_transfer_sizeof(member)}} * memberLength);
400                     {% else %}
401                         //* This loop cannot overflow because it iterates up to |memberLength|. Even
402                         //* if memberLength were the maximum integer value, |i| would become equal
403                         //* to it just before exiting the loop, but not increment past or wrap
404                         //* around.
405                         for (decltype(memberLength) i = 0; i < memberLength; ++i) {
406                             {{deserialize_member(member, "memberBuffer[i]", "copiedMembers[i]")}}
407                         }
408                     {% endif %}
409                 {% endif %}
410             }
411         {% endfor %}
412 
413         return WireResult::Success;
414     }
415     DAWN_UNUSED_FUNC({{Return}}{{name}}Deserialize);
416 {% endmacro %}
417 
418 {% macro write_command_serialization_methods(command, is_return) %}
419     {% set Return = "Return" if is_return else "" %}
420     {% set Name = Return + command.name.CamelCase() %}
421     {% set Cmd = Name + "Cmd" %}
422 
423     size_t {{Cmd}}::GetRequiredSize() const {
424         size_t size = sizeof({{Name}}Transfer) + {{Name}}GetExtraRequiredSize(*this);
425         return size;
426     }
427 
428     {% if command.may_have_dawn_object %}
429         WireResult {{Cmd}}::Serialize(
430             size_t commandSize,
431             SerializeBuffer* buffer,
432             const ObjectIdProvider& provider
433         ) const {
434             {{Name}}Transfer* transfer;
435             WIRE_TRY(buffer->Next(&transfer));
436             transfer->commandSize = commandSize;
437             return ({{Name}}Serialize(*this, transfer, buffer, provider));
438         }
439         WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer) const {
440             ErrorObjectIdProvider provider;
441             return Serialize(commandSize, buffer, provider);
442         }
443 
444         WireResult {{Cmd}}::Deserialize(
445             DeserializeBuffer* deserializeBuffer,
446             DeserializeAllocator* allocator,
447             const ObjectIdResolver& resolver
448         ) {
449             const volatile {{Name}}Transfer* transfer;
450             WIRE_TRY(deserializeBuffer->Read(&transfer));
451             return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator, resolver);
452         }
453         WireResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator) {
454             ErrorObjectIdResolver resolver;
455             return Deserialize(deserializeBuffer, allocator, resolver);
456         }
457     {% else %}
458         WireResult {{Cmd}}::Serialize(size_t commandSize, SerializeBuffer* buffer) const {
459             {{Name}}Transfer* transfer;
460             WIRE_TRY(buffer->Next(&transfer));
461             transfer->commandSize = commandSize;
462             return ({{Name}}Serialize(*this, transfer, buffer));
463         }
464         WireResult {{Cmd}}::Serialize(
465             size_t commandSize,
466             SerializeBuffer* buffer,
467             const ObjectIdProvider&
468         ) const {
469             return Serialize(commandSize, buffer);
470         }
471 
472         WireResult {{Cmd}}::Deserialize(DeserializeBuffer* deserializeBuffer, DeserializeAllocator* allocator) {
473             const volatile {{Name}}Transfer* transfer;
474             WIRE_TRY(deserializeBuffer->Read(&transfer));
475             return {{Name}}Deserialize(this, transfer, deserializeBuffer, allocator);
476         }
477         WireResult {{Cmd}}::Deserialize(
478             DeserializeBuffer* deserializeBuffer,
479             DeserializeAllocator* allocator,
480             const ObjectIdResolver&
481         ) {
482             return Deserialize(deserializeBuffer, allocator);
483         }
484     {% endif %}
485 {% endmacro %}
486 
487 {% macro make_chained_struct_serialization_helpers(out=None) %}
488         {% set ChainedStructPtr = "WGPUChainedStructOut*" if out else "const WGPUChainedStruct*" %}
489         {% set ChainedStruct = "WGPUChainedStructOut" if out else "WGPUChainedStruct" %}
490         size_t GetChainedStructExtraRequiredSize({{ChainedStructPtr}} chainedStruct) {
491             ASSERT(chainedStruct != nullptr);
492             size_t result = 0;
493             while (chainedStruct != nullptr) {
494                 switch (chainedStruct->sType) {
495                     {% for sType in types["s type"].values if (
496                             sType.valid and
497                             (sType.name.CamelCase() not in client_side_structures) and
498                             (types[sType.name.get()].output == out)
499                     ) %}
500                         case {{as_cEnum(types["s type"].name, sType.name)}}: {
501                             const auto& typedStruct = *reinterpret_cast<{{as_cType(sType.name)}} const *>(chainedStruct);
502                             result += sizeof({{as_cType(sType.name)}}Transfer);
503                             result += {{as_cType(sType.name)}}GetExtraRequiredSize(typedStruct);
504                             chainedStruct = typedStruct.chain.next;
505                             break;
506                         }
507                     {% endfor %}
508                     // Explicitly list the Invalid enum. MSVC complains about no case labels.
509                     case WGPUSType_Invalid:
510                     default:
511                         // Invalid enum. Reserve space just for the transfer header (sType and hasNext).
512                         result += sizeof(WGPUChainedStructTransfer);
513                         chainedStruct = chainedStruct->next;
514                         break;
515                 }
516             }
517             return result;
518         }
519 
520         DAWN_NO_DISCARD WireResult SerializeChainedStruct({{ChainedStructPtr}} chainedStruct,
521                                                           SerializeBuffer* buffer,
522                                                           const ObjectIdProvider& provider) {
523             ASSERT(chainedStruct != nullptr);
524             ASSERT(buffer != nullptr);
525             do {
526                 switch (chainedStruct->sType) {
527                     {% for sType in types["s type"].values if (
528                             sType.valid and
529                             (sType.name.CamelCase() not in client_side_structures) and
530                             (types[sType.name.get()].output == out)
531                     ) %}
532                         {% set CType = as_cType(sType.name) %}
533                         case {{as_cEnum(types["s type"].name, sType.name)}}: {
534 
535                             {{CType}}Transfer* transfer;
536                             WIRE_TRY(buffer->Next(&transfer));
537                             transfer->chain.sType = chainedStruct->sType;
538                             transfer->chain.hasNext = chainedStruct->next != nullptr;
539 
540                             WIRE_TRY({{CType}}Serialize(*reinterpret_cast<{{CType}} const*>(chainedStruct), transfer, buffer
541                                 {%- if types[sType.name.get()].may_have_dawn_object -%}
542                                 , provider
543                                 {%- endif -%}
544                             ));
545 
546                             chainedStruct = chainedStruct->next;
547                         } break;
548                     {% endfor %}
549                     // Explicitly list the Invalid enum. MSVC complains about no case labels.
550                     case WGPUSType_Invalid:
551                     default: {
552                         // Invalid enum. Serialize just the transfer header with Invalid as the sType.
553                         // TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
554                         if (chainedStruct->sType != WGPUSType_Invalid) {
555                             dawn::WarningLog() << "Unknown sType " << chainedStruct->sType << " discarded.";
556                         }
557 
558                         WGPUChainedStructTransfer* transfer;
559                         WIRE_TRY(buffer->Next(&transfer));
560                         transfer->sType = WGPUSType_Invalid;
561                         transfer->hasNext = chainedStruct->next != nullptr;
562 
563                         // Still move on in case there are valid structs after this.
564                         chainedStruct = chainedStruct->next;
565                         break;
566                     }
567                 }
568             } while (chainedStruct != nullptr);
569             return WireResult::Success;
570         }
571 
572         WireResult DeserializeChainedStruct({{ChainedStructPtr}}* outChainNext,
573                                             DeserializeBuffer* deserializeBuffer,
574                                             DeserializeAllocator* allocator,
575                                             const ObjectIdResolver& resolver) {
576             bool hasNext;
577             do {
578                 const volatile WGPUChainedStructTransfer* header;
579                 WIRE_TRY(deserializeBuffer->Peek(&header));
580                 WGPUSType sType = header->sType;
581                 switch (sType) {
582                     {% for sType in types["s type"].values if (
583                             sType.valid and
584                             (sType.name.CamelCase() not in client_side_structures) and
585                             (types[sType.name.get()].output == out)
586                     ) %}
587                         {% set CType = as_cType(sType.name) %}
588                         case {{as_cEnum(types["s type"].name, sType.name)}}: {
589                             const volatile {{CType}}Transfer* transfer;
590                             WIRE_TRY(deserializeBuffer->Read(&transfer));
591 
592                             {{CType}}* outStruct;
593                             WIRE_TRY(GetSpace(allocator, sizeof({{CType}}), &outStruct));
594                             outStruct->chain.sType = sType;
595                             outStruct->chain.next = nullptr;
596 
597                             *outChainNext = &outStruct->chain;
598                             outChainNext = &outStruct->chain.next;
599 
600                             WIRE_TRY({{CType}}Deserialize(outStruct, transfer, deserializeBuffer, allocator
601                                 {%- if types[sType.name.get()].may_have_dawn_object -%}
602                                     , resolver
603                                 {%- endif -%}
604                             ));
605 
606                             hasNext = transfer->chain.hasNext;
607                         } break;
608                     {% endfor %}
609                     // Explicitly list the Invalid enum. MSVC complains about no case labels.
610                     case WGPUSType_Invalid:
611                     default: {
612                         // Invalid enum. Deserialize just the transfer header with Invalid as the sType.
613                         // TODO(crbug.com/dawn/369): Unknown sTypes are silently discarded.
614                         if (sType != WGPUSType_Invalid) {
615                             dawn::WarningLog() << "Unknown sType " << sType << " discarded.";
616                         }
617 
618                         const volatile WGPUChainedStructTransfer* transfer;
619                         WIRE_TRY(deserializeBuffer->Read(&transfer));
620 
621                         {{ChainedStruct}}* outStruct;
622                         WIRE_TRY(GetSpace(allocator, sizeof({{ChainedStruct}}), &outStruct));
623                         outStruct->sType = WGPUSType_Invalid;
624                         outStruct->next = nullptr;
625 
626                         // Still move on in case there are valid structs after this.
627                         *outChainNext = outStruct;
628                         outChainNext = &outStruct->next;
629                         hasNext = transfer->hasNext;
630                         break;
631                     }
632                 }
633             } while (hasNext);
634 
635             return WireResult::Success;
636         }
637 {% endmacro %}
638 
639 namespace dawn_wire {
640 
641     ObjectHandle::ObjectHandle() = default;
642     ObjectHandle::ObjectHandle(ObjectId id, ObjectGeneration generation)
643         : id(id), generation(generation) {
644     }
645 
646     ObjectHandle::ObjectHandle(const volatile ObjectHandle& rhs)
647         : id(rhs.id), generation(rhs.generation) {
648     }
649     ObjectHandle& ObjectHandle::operator=(const volatile ObjectHandle& rhs) {
650         id = rhs.id;
651         generation = rhs.generation;
652         return *this;
653     }
654 
655     ObjectHandle& ObjectHandle::AssignFrom(const ObjectHandle& rhs) {
656         id = rhs.id;
657         generation = rhs.generation;
658         return *this;
659     }
660     ObjectHandle& ObjectHandle::AssignFrom(const volatile ObjectHandle& rhs) {
661         id = rhs.id;
662         generation = rhs.generation;
663         return *this;
664     }
665 
666     namespace {
667         // Allocates enough space from allocator to countain T[count] and return it in out.
668         // Return FatalError if the allocator couldn't allocate the memory.
669         // Always writes to |out| on success.
670         template <typename T, typename N>
671         WireResult GetSpace(DeserializeAllocator* allocator, N count, T** out) {
672             constexpr size_t kMaxCountWithoutOverflows = std::numeric_limits<size_t>::max() / sizeof(T);
673             if (count > kMaxCountWithoutOverflows) {
674                 return WireResult::FatalError;
675             }
676 
677             size_t totalSize = sizeof(T) * count;
678             *out = static_cast<T*>(allocator->GetSpace(totalSize));
679             if (*out == nullptr) {
680                 return WireResult::FatalError;
681             }
682 
683             return WireResult::Success;
684         }
685 
686         struct WGPUChainedStructTransfer {
687             WGPUSType sType;
688             bool hasNext;
689         };
690 
691         size_t GetChainedStructExtraRequiredSize(const WGPUChainedStruct* chainedStruct);
692         DAWN_NO_DISCARD WireResult SerializeChainedStruct(const WGPUChainedStruct* chainedStruct,
693                                                           SerializeBuffer* buffer,
694                                                           const ObjectIdProvider& provider);
695         WireResult DeserializeChainedStruct(const WGPUChainedStruct** outChainNext,
696                                             DeserializeBuffer* deserializeBuffer,
697                                             DeserializeAllocator* allocator,
698                                             const ObjectIdResolver& resolver);
699 
700         size_t GetChainedStructExtraRequiredSize(WGPUChainedStructOut* chainedStruct);
701         DAWN_NO_DISCARD WireResult SerializeChainedStruct(WGPUChainedStructOut* chainedStruct,
702                                                           SerializeBuffer* buffer,
703                                                           const ObjectIdProvider& provider);
704         WireResult DeserializeChainedStruct(WGPUChainedStructOut** outChainNext,
705                                             DeserializeBuffer* deserializeBuffer,
706                                             DeserializeAllocator* allocator,
707                                             const ObjectIdResolver& resolver);
708 
709         //* Output structure [de]serialization first because it is used by commands.
710         {% for type in by_category["structure"] %}
711             {% set name = as_cType(type.name) %}
712             {% if type.name.CamelCase() not in client_side_structures %}
713                 {{write_record_serialization_helpers(type, name, type.members, is_cmd=False)}}
714             {% endif %}
715         {% endfor %}
716 
717 
718         {{ make_chained_struct_serialization_helpers(out=False) }}
719         {{ make_chained_struct_serialization_helpers(out=True) }}
720 
721         //* Output [de]serialization helpers for commands
722         {% for command in cmd_records["command"] %}
723             {% set name = command.name.CamelCase() %}
724             {{write_record_serialization_helpers(command, name, command.members, is_cmd=True)}}
725         {% endfor %}
726 
727         //* Output [de]serialization helpers for return commands
728         {% for command in cmd_records["return command"] %}
729             {% set name = command.name.CamelCase() %}
730             {{write_record_serialization_helpers(command, name, command.members,
731                                                  is_cmd=True, is_return_command=True)}}
732         {% endfor %}
733 
734         // Implementation of ObjectIdResolver that always errors.
735         // Used when the generator adds a provider argument because of a chained
736         // struct, but in practice, a chained struct in that location is invalid.
737         class ErrorObjectIdResolver final : public ObjectIdResolver {
738             public:
739                 {% for type in by_category["object"] %}
740                     WireResult GetFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
741                         return WireResult::FatalError;
742                     }
743                     WireResult GetOptionalFromId(ObjectId id, {{as_cType(type.name)}}* out) const override {
744                         return WireResult::FatalError;
745                     }
746                 {% endfor %}
747         };
748 
749         // Implementation of ObjectIdProvider that always errors.
750         // Used when the generator adds a provider argument because of a chained
751         // struct, but in practice, a chained struct in that location is invalid.
752         class ErrorObjectIdProvider final : public ObjectIdProvider {
753             public:
754                 {% for type in by_category["object"] %}
755                     WireResult GetId({{as_cType(type.name)}} object, ObjectId* out) const override {
756                         return WireResult::FatalError;
757                     }
758                     WireResult GetOptionalId({{as_cType(type.name)}} object, ObjectId* out) const override {
759                         return WireResult::FatalError;
760                     }
761                 {% endfor %}
762         };
763 
764     }  // anonymous namespace
765 
766     {% for command in cmd_records["command"] %}
767         {{ write_command_serialization_methods(command, False) }}
768     {% endfor %}
769 
770     {% for command in cmd_records["return command"] %}
771         {{ write_command_serialization_methods(command, True) }}
772     {% endfor %}
773 
774     // Implementations of serialization/deserialization of WPGUDeviceProperties.
775     size_t SerializedWGPUDevicePropertiesSize(const WGPUDeviceProperties* deviceProperties) {
776         return sizeof(WGPUDeviceProperties) +
777                WGPUDevicePropertiesGetExtraRequiredSize(*deviceProperties);
778     }
779 
780     void SerializeWGPUDeviceProperties(const WGPUDeviceProperties* deviceProperties,
781                                        char* buffer) {
782         SerializeBuffer serializeBuffer(buffer, SerializedWGPUDevicePropertiesSize(deviceProperties));
783 
784         WGPUDevicePropertiesTransfer* transfer;
785 
786         WireResult result = serializeBuffer.Next(&transfer);
787         ASSERT(result == WireResult::Success);
788 
789         ErrorObjectIdProvider provider;
790         result = WGPUDevicePropertiesSerialize(*deviceProperties, transfer, &serializeBuffer, provider);
791         ASSERT(result == WireResult::Success);
792     }
793 
794     bool DeserializeWGPUDeviceProperties(WGPUDeviceProperties* deviceProperties,
795                                          const volatile char* buffer,
796                                          size_t size) {
797         const volatile WGPUDevicePropertiesTransfer* transfer;
798         DeserializeBuffer deserializeBuffer(buffer, size);
799         if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
800             return false;
801         }
802 
803         ErrorObjectIdResolver resolver;
804         return WGPUDevicePropertiesDeserialize(deviceProperties, transfer, &deserializeBuffer,
805                                                nullptr, resolver) == WireResult::Success;
806     }
807 
808     size_t SerializedWGPUSupportedLimitsSize(const WGPUSupportedLimits* supportedLimits) {
809         return sizeof(WGPUSupportedLimits) +
810                WGPUSupportedLimitsGetExtraRequiredSize(*supportedLimits);
811     }
812 
813     void SerializeWGPUSupportedLimits(
814         const WGPUSupportedLimits* supportedLimits,
815         char* buffer) {
816         SerializeBuffer serializeBuffer(buffer, SerializedWGPUSupportedLimitsSize(supportedLimits));
817 
818         WGPUSupportedLimitsTransfer* transfer;
819 
820         WireResult result = serializeBuffer.Next(&transfer);
821         ASSERT(result == WireResult::Success);
822 
823         ErrorObjectIdProvider provider;
824         result = WGPUSupportedLimitsSerialize(*supportedLimits, transfer, &serializeBuffer, provider);
825         ASSERT(result == WireResult::Success);
826     }
827 
828     bool DeserializeWGPUSupportedLimits(WGPUSupportedLimits* supportedLimits,
829                                         const volatile char* buffer,
830                                         size_t size) {
831         const volatile WGPUSupportedLimitsTransfer* transfer;
832         DeserializeBuffer deserializeBuffer(buffer, size);
833         if (deserializeBuffer.Read(&transfer) != WireResult::Success) {
834             return false;
835         }
836 
837         ErrorObjectIdResolver resolver;
838         return WGPUSupportedLimitsDeserialize(supportedLimits, transfer, &deserializeBuffer,
839                                               nullptr, resolver) == WireResult::Success;
840     }
841 
842 }  // namespace dawn_wire
843