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