1 // Copyright 2017 The Fuchsia Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #pragma once 6 7 namespace fidl { 8 namespace internal { 9 10 // Some assumptions about data type layout. 11 static_assert(offsetof(fidl_string_t, size) == 0u, ""); 12 static_assert(offsetof(fidl_string_t, data) == 8u, ""); 13 14 static_assert(offsetof(fidl_vector_t, count) == 0u, ""); 15 static_assert(offsetof(fidl_vector_t, data) == 8u, ""); 16 17 static_assert(ZX_HANDLE_INVALID == FIDL_HANDLE_ABSENT, ""); 18 19 template <bool kConst, class U> 20 struct SetPtrConst; 21 22 template <class U> 23 struct SetPtrConst<false, U> { 24 typedef U* type; 25 }; 26 27 template <class U> 28 struct SetPtrConst<true, U> { 29 typedef const U* type; 30 }; 31 32 // Walks over a FIDL buffer and validates/encodes/decodes it per-Derived. 33 // 34 // kMutating controls whether this deals with mutable bytes or immutable bytes 35 // (validation wants immutable, encode/decode wants mutable) 36 // 37 // kContinueAfterErrors controls whether parsing is continued upon failure (encode needs this to 38 // see all available handles). 39 // 40 // Derived should offer the following methods: 41 // 42 // const? uint8_t* bytes() - returns the start of the buffer of bytes 43 // uint32_t num_bytes() - returns the number of bytes in said buffer 44 // uint32_t num_handles() - returns the number of handles that are claimable 45 // bool ValidateOutOfLineStorageClaim(const void* a, const void* b) 46 // - returns true if a legally points to b 47 // void UnclaimedHandle(zx_handle_t*) - notes that a handle was skipped 48 // void ClaimedHandle(zx_handle_t*, uint32_t idx) - notes that a handle was claimed 49 // PointerState GetPointerState(const void* ptr) - returns whether a pointer is present or not 50 // HandleState GetHandleState(zx_handle_t) - returns if a handle is present or not 51 // void UpdatePointer(T**p, T*v) - mutates a pointer representation for a present pointer 52 // void SetError(const char* error_msg) - flags that an error occurred 53 template <class Derived, bool kMutating, bool kContinueAfterErrors> 54 class BufferWalker { 55 public: 56 explicit BufferWalker(const fidl_type* type) 57 : type_(type) {} 58 59 void Walk() { 60 // The first decode is special. It must be a struct or a table. 61 // We need to know the size of the first element to compute the start of 62 // the out-of-line allocations. 63 64 if (type_ == nullptr) { 65 SetError("Cannot decode a null fidl type"); 66 return; 67 } 68 69 if (bytes() == nullptr) { 70 SetError("Cannot decode null bytes"); 71 return; 72 } 73 74 switch (type_->type_tag) { 75 case fidl::kFidlTypeStruct: 76 if (num_bytes() < type_->coded_struct.size) { 77 SetError("Message size is smaller than expected"); 78 return; 79 } 80 out_of_line_offset_ = static_cast<uint32_t>(fidl::FidlAlign(type_->coded_struct.size)); 81 break; 82 case fidl::kFidlTypeTable: 83 if (num_bytes() < sizeof(fidl_vector_t)) { 84 SetError("Message size is smaller than expected"); 85 return; 86 } 87 out_of_line_offset_ = static_cast<uint32_t>(fidl::FidlAlign(sizeof(fidl_vector_t))); 88 break; 89 default: 90 SetError("Message must be a struct or a table"); 91 return; 92 } 93 94 Push(Frame::DoneSentinel()); 95 Push(Frame(type_, 0u)); 96 97 // Macro to insert the relevant goop required to support two control flows here: 98 // one where we keep reading after error, and another where we return immediately. 99 // No runtime overhead thanks to if constexpr magic. 100 #define FIDL_POP_AND_CONTINUE_OR_RETURN \ 101 if (kContinueAfterErrors) { \ 102 Pop(); \ 103 continue; \ 104 } else { \ 105 return; \ 106 } 107 108 for (;;) { 109 Frame* frame = Peek(); 110 111 switch (frame->state) { 112 case Frame::kStateStruct: { 113 const uint32_t field_index = frame->NextStructField(); 114 if (field_index == frame->struct_state.field_count) { 115 Pop(); 116 continue; 117 } 118 const fidl::FidlField& field = frame->struct_state.fields[field_index]; 119 const fidl_type_t* field_type = field.type; 120 const uint32_t field_offset = frame->offset + field.offset; 121 if (!Push(Frame(field_type, field_offset))) { 122 SetError("recursion depth exceeded processing struct"); 123 FIDL_POP_AND_CONTINUE_OR_RETURN; 124 } 125 continue; 126 } 127 case Frame::kStateStructPointer: { 128 switch (GetPointerState(TypedAt<void>(frame->offset))) { 129 case PointerState::PRESENT: 130 break; 131 case PointerState::ABSENT: 132 Pop(); 133 continue; 134 default: 135 SetError("Tried to decode a bad struct pointer"); 136 FIDL_POP_AND_CONTINUE_OR_RETURN; 137 } 138 auto struct_ptr_ptr = TypedAt<void*>(frame->offset); 139 if (!ClaimOutOfLineStorage(frame->struct_pointer_state.struct_type->size, 140 *struct_ptr_ptr, &frame->offset)) { 141 SetError("message wanted to store too large of a nullable struct"); 142 FIDL_POP_AND_CONTINUE_OR_RETURN; 143 } 144 UpdatePointer(struct_ptr_ptr, TypedAt<void>(frame->offset)); 145 const fidl::FidlCodedStruct* coded_struct = frame->struct_pointer_state.struct_type; 146 *frame = Frame(coded_struct, frame->offset); 147 continue; 148 } 149 case Frame::kStateTable: { 150 if (frame->field == 0u) { 151 auto envelope_vector_ptr = TypedAt<fidl_vector_t>(frame->offset); 152 switch (GetPointerState(&envelope_vector_ptr->data)) { 153 case PointerState::PRESENT: 154 break; 155 case PointerState::ABSENT: 156 SetError("Table data cannot be absent"); 157 FIDL_POP_AND_CONTINUE_OR_RETURN; 158 default: 159 SetError("message tried to decode a non-present vector"); 160 FIDL_POP_AND_CONTINUE_OR_RETURN; 161 } 162 uint32_t size; 163 if (mul_overflow(envelope_vector_ptr->count, 2 * sizeof(uint64_t), &size)) { 164 SetError("integer overflow calculating table size"); 165 FIDL_POP_AND_CONTINUE_OR_RETURN; 166 } 167 if (!ClaimOutOfLineStorage(size, envelope_vector_ptr->data, &frame->offset)) { 168 SetError("message wanted to store too large of a table"); 169 FIDL_POP_AND_CONTINUE_OR_RETURN; 170 } 171 UpdatePointer(&envelope_vector_ptr->data, TypedAt<void>(frame->offset)); 172 frame->field = 1; 173 frame->table_state.known_index = 0; 174 frame->table_state.present_count = static_cast<uint32_t>(envelope_vector_ptr->count); 175 frame->table_state.end_offset = out_of_line_offset_; 176 frame->table_state.end_handle = handle_idx_; 177 continue; 178 } 179 if (frame->table_state.end_offset != out_of_line_offset_) { 180 SetError("Table field was mis-sized"); 181 FIDL_POP_AND_CONTINUE_OR_RETURN; 182 } 183 if (frame->table_state.end_handle != handle_idx_) { 184 SetError("Table handles were mis-sized"); 185 FIDL_POP_AND_CONTINUE_OR_RETURN; 186 } 187 if (frame->field > frame->table_state.present_count) { 188 Pop(); 189 continue; 190 } 191 const fidl::FidlTableField* known_field = nullptr; 192 if (frame->table_state.known_index < frame->table_state.field_count) { 193 const fidl::FidlTableField* field = 194 &frame->table_state.fields[frame->table_state.known_index]; 195 if (field->ordinal == frame->field) { 196 known_field = field; 197 frame->table_state.known_index++; 198 } 199 } 200 const uint32_t tag_offset = static_cast<uint32_t>( 201 frame->offset + (frame->field - 1) * 2 * sizeof(uint64_t)); 202 const uint32_t data_offset = static_cast<uint32_t>( 203 tag_offset + sizeof(uint64_t)); 204 const uint64_t packed_sizes = *TypedAt<uint64_t>(tag_offset); 205 frame->field++; 206 switch (GetPointerState(TypedAt<void>(data_offset))) { 207 case PointerState::PRESENT: 208 if (packed_sizes != 0) 209 break; // expected 210 211 SetError("Table envelope has present data pointer, but no data, and no handles"); 212 FIDL_POP_AND_CONTINUE_OR_RETURN; 213 case PointerState::ABSENT: 214 if (packed_sizes == 0) 215 continue; // skip 216 217 SetError("Table envelope has absent data pointer, yet has data and/or handles"); 218 FIDL_POP_AND_CONTINUE_OR_RETURN; 219 default: 220 SetError("Table envelope has bad data pointer"); 221 FIDL_POP_AND_CONTINUE_OR_RETURN; 222 } 223 uint32_t offset; 224 uint32_t handles; 225 const uint32_t table_bytes = static_cast<uint32_t>(packed_sizes & 0xffffffffu); 226 const uint32_t table_handles = static_cast<uint32_t>(packed_sizes >> 32); 227 if (add_overflow(out_of_line_offset_, table_bytes, &offset) || offset > num_bytes()) { 228 SetError("integer overflow decoding table field"); 229 FIDL_POP_AND_CONTINUE_OR_RETURN; 230 } 231 if (add_overflow(handle_idx_, table_handles, &handles) || 232 handles > num_handles()) { 233 SetError("integer overflow decoding table handles"); 234 FIDL_POP_AND_CONTINUE_OR_RETURN; 235 } 236 frame->table_state.end_offset = offset; 237 frame->table_state.end_handle = handles; 238 if (known_field != nullptr) { 239 const fidl_type_t* field_type = known_field->type; 240 uint32_t field_offset; 241 if (!ClaimOutOfLineStorage(TypeSize(field_type), TypedAt<void*>(data_offset), &field_offset)) { 242 SetError("table wanted too many bytes in field"); 243 FIDL_POP_AND_CONTINUE_OR_RETURN; 244 } 245 UpdatePointer(TypedAt<void*>(data_offset), TypedAt<void>(field_offset)); 246 if (!Push(Frame(field_type, field_offset))) { 247 SetError("recursion depth exceeded decoding table"); 248 FIDL_POP_AND_CONTINUE_OR_RETURN; 249 } 250 } else { 251 // Table data will not be processed: discard it. 252 uint32_t field_offset; 253 if (!ClaimOutOfLineStorage(table_bytes, TypedAt<void*>(data_offset), &field_offset)) { 254 SetError("table wanted too many bytes in field"); 255 FIDL_POP_AND_CONTINUE_OR_RETURN; 256 } 257 UpdatePointer(TypedAt<void*>(data_offset), TypedAt<void>(field_offset)); 258 for (uint32_t i = 0; i < table_handles; i++) { 259 if (!ClaimHandle(nullptr)) { 260 SetError("expected handle not present"); 261 FIDL_POP_AND_CONTINUE_OR_RETURN; 262 } 263 } 264 } 265 continue; 266 } 267 case Frame::kStateTablePointer: { 268 switch (GetPointerState(TypedAt<void>(frame->offset))) { 269 case PointerState::PRESENT: 270 break; 271 case PointerState::ABSENT: 272 Pop(); 273 continue; 274 default: 275 SetError("Tried to decode a bad table pointer"); 276 FIDL_POP_AND_CONTINUE_OR_RETURN; 277 } 278 auto table_ptr_ptr = TypedAt<void*>(frame->offset); 279 if (!ClaimOutOfLineStorage(sizeof(fidl_vector_t), *table_ptr_ptr, &frame->offset)) { 280 SetError("message wanted to store too large of a nullable table"); 281 FIDL_POP_AND_CONTINUE_OR_RETURN; 282 } 283 UpdatePointer(table_ptr_ptr, TypedAt<void>(frame->offset)); 284 const fidl::FidlCodedTable* coded_table = frame->table_pointer_state.table_type; 285 *frame = Frame(coded_table, frame->offset); 286 continue; 287 } 288 case Frame::kStateUnion: { 289 fidl_union_tag_t union_tag = *TypedAt<fidl_union_tag_t>(frame->offset); 290 if (union_tag >= frame->union_state.type_count) { 291 SetError("Tried to decode a bad union discriminant"); 292 FIDL_POP_AND_CONTINUE_OR_RETURN; 293 } 294 const fidl_type_t* member = frame->union_state.types[union_tag]; 295 if (!member) { 296 Pop(); 297 continue; 298 } 299 frame->offset += frame->union_state.data_offset; 300 *frame = Frame(member, frame->offset); 301 continue; 302 } 303 case Frame::kStateUnionPointer: { 304 auto union_ptr_ptr = TypedAt<fidl_union_tag_t*>(frame->offset); 305 switch (GetPointerState(TypedAt<void>(frame->offset))) { 306 case PointerState::PRESENT: 307 break; 308 case PointerState::ABSENT: 309 Pop(); 310 continue; 311 default: 312 SetError("Tried to decode a bad union pointer"); 313 FIDL_POP_AND_CONTINUE_OR_RETURN; 314 } 315 if (!ClaimOutOfLineStorage(frame->union_pointer_state.union_type->size, *union_ptr_ptr, 316 &frame->offset)) { 317 SetError("message wanted to store too large of a nullable union"); 318 FIDL_POP_AND_CONTINUE_OR_RETURN; 319 } 320 UpdatePointer(union_ptr_ptr, TypedAt<fidl_union_tag_t>(frame->offset)); 321 const fidl::FidlCodedUnion* coded_union = frame->union_pointer_state.union_type; 322 *frame = Frame(coded_union, frame->offset); 323 continue; 324 } 325 case Frame::kStateArray: { 326 const uint32_t element_offset = frame->NextArrayOffset(); 327 if (element_offset == frame->array_state.array_size) { 328 Pop(); 329 continue; 330 } 331 const fidl_type_t* element_type = frame->array_state.element; 332 const uint32_t offset = frame->offset + element_offset; 333 if (!Push(Frame(element_type, offset))) { 334 SetError("recursion depth exceeded decoding array"); 335 FIDL_POP_AND_CONTINUE_OR_RETURN; 336 } 337 continue; 338 } 339 case Frame::kStateString: { 340 auto string_ptr = TypedAt<fidl_string_t>(frame->offset); 341 // The string storage may be Absent for nullable strings and must 342 // otherwise be Present. No other values are allowed. 343 switch (GetPointerState(&string_ptr->data)) { 344 case PointerState::PRESENT: 345 break; 346 case PointerState::ABSENT: 347 if (!frame->string_state.nullable) { 348 SetError("message tried to decode an absent non-nullable string"); 349 FIDL_POP_AND_CONTINUE_OR_RETURN; 350 } 351 if (string_ptr->size != 0u) { 352 SetError("message tried to decode an absent string of non-zero length"); 353 FIDL_POP_AND_CONTINUE_OR_RETURN; 354 } 355 Pop(); 356 continue; 357 default: 358 SetError( 359 "message tried to decode a string that is neither present nor absent"); 360 FIDL_POP_AND_CONTINUE_OR_RETURN; 361 } 362 uint64_t bound = frame->string_state.max_size; 363 uint64_t size = string_ptr->size; 364 if (size > bound) { 365 SetError("message tried to decode too large of a bounded string"); 366 FIDL_POP_AND_CONTINUE_OR_RETURN; 367 } 368 uint32_t string_data_offset = 0u; 369 if (!ClaimOutOfLineStorage(static_cast<uint32_t>(size), string_ptr->data, &string_data_offset)) { 370 SetError("decoding a string overflowed buffer"); 371 FIDL_POP_AND_CONTINUE_OR_RETURN; 372 } 373 UpdatePointer(&string_ptr->data, TypedAt<char>(string_data_offset)); 374 Pop(); 375 continue; 376 } 377 case Frame::kStateHandle: { 378 auto handle_ptr = TypedAt<zx_handle_t>(frame->offset); 379 // The handle storage may be Absent for nullable handles and must 380 // otherwise be Present. No other values are allowed. 381 switch (GetHandleState(*handle_ptr)) { 382 case HandleState::ABSENT: 383 if (frame->handle_state.nullable) { 384 Pop(); 385 continue; 386 } 387 SetError("message tried to decode a non-present handle"); 388 FIDL_POP_AND_CONTINUE_OR_RETURN; 389 case HandleState::PRESENT: 390 if (!ClaimHandle(handle_ptr)) { 391 SetError("message decoded too many handles"); 392 FIDL_POP_AND_CONTINUE_OR_RETURN; 393 } 394 Pop(); 395 continue; 396 default: 397 // The value at the handle was garbage. 398 SetError("message tried to decode a garbage handle"); 399 FIDL_POP_AND_CONTINUE_OR_RETURN; 400 } 401 } 402 case Frame::kStateVector: { 403 auto vector_ptr = TypedAt<fidl_vector_t>(frame->offset); 404 // The vector storage may be Absent for nullable vectors and must 405 // otherwise be Present. No other values are allowed. 406 switch (GetPointerState(&vector_ptr->data)) { 407 case PointerState::PRESENT: 408 break; 409 case PointerState::ABSENT: 410 if (!frame->vector_state.nullable) { 411 SetError("message tried to decode an absent non-nullable vector"); 412 FIDL_POP_AND_CONTINUE_OR_RETURN; 413 } 414 if (vector_ptr->count != 0u) { 415 SetError("message tried to decode an absent vector of non-zero elements"); 416 FIDL_POP_AND_CONTINUE_OR_RETURN; 417 } 418 Pop(); 419 continue; 420 default: 421 SetError("message tried to decode a non-present vector"); 422 FIDL_POP_AND_CONTINUE_OR_RETURN; 423 } 424 if (vector_ptr->count > frame->vector_state.max_count) { 425 SetError("message tried to decode too large of a bounded vector"); 426 FIDL_POP_AND_CONTINUE_OR_RETURN; 427 } 428 uint32_t size; 429 if (mul_overflow(vector_ptr->count, frame->vector_state.element_size, &size)) { 430 SetError("integer overflow calculating vector size"); 431 FIDL_POP_AND_CONTINUE_OR_RETURN; 432 } 433 if (!ClaimOutOfLineStorage(size, vector_ptr->data, &frame->offset)) { 434 SetError("message wanted to store too large of a vector"); 435 FIDL_POP_AND_CONTINUE_OR_RETURN; 436 } 437 UpdatePointer(&vector_ptr->data, TypedAt<void>(frame->offset)); 438 if (frame->vector_state.element) { 439 // Continue by decoding the vector elements as an array. 440 *frame = Frame(frame->vector_state.element, size, 441 frame->vector_state.element_size, frame->offset); 442 } else { 443 // If there is no element type pointer, there is 444 // nothing to decode in the vector secondary 445 // payload. So just continue. 446 Pop(); 447 } 448 continue; 449 } 450 case Frame::kStateDone: { 451 if (out_of_line_offset_ != num_bytes()) { 452 SetError("message did not decode all provided bytes"); 453 } 454 return; 455 } 456 } 457 } 458 459 #undef FIDL_POP_AND_CONTINUE_OR_RETURN 460 } 461 462 protected: 463 void SetError(const char* error_msg) { 464 derived()->SetError(error_msg); 465 } 466 467 template <typename T> 468 typename SetPtrConst<!kMutating, T>::type TypedAt(uint32_t offset) const { 469 return reinterpret_cast<typename SetPtrConst<!kMutating, T>::type>(bytes() + offset); 470 } 471 472 enum class PointerState : uintptr_t { 473 PRESENT = FIDL_ALLOC_PRESENT, 474 ABSENT = FIDL_ALLOC_ABSENT, 475 INVALID = 1 // *OR* *ANY* non PRESENT/ABSENT value. 476 }; 477 478 enum class HandleState : zx_handle_t { 479 PRESENT = FIDL_HANDLE_PRESENT, 480 ABSENT = FIDL_HANDLE_ABSENT, 481 INVALID = 1 // *OR* *ANY* non PRESENT/ABSENT value. 482 }; 483 484 uint32_t handle_idx() const { return handle_idx_; } 485 486 private: 487 Derived* derived() { 488 return static_cast<Derived*>(this); 489 } 490 491 const Derived* derived() const { 492 return static_cast<const Derived*>(this); 493 } 494 495 // Returns a pointer to the bytes in the message. 496 auto bytes() const { 497 return derived()->bytes(); 498 } 499 500 // Returns the number of bytes in the message. 501 auto num_bytes() const { 502 return derived()->num_bytes(); 503 } 504 505 // Returns the number of handles in the message (encoding: the max number of handles in the message). 506 auto num_handles() const { 507 return derived()->num_handles(); 508 } 509 510 // Returns PRESENT/ABSENT/INVALID for a given pointer value. 511 PointerState GetPointerState(const void* ptr) const { 512 return derived()->GetPointerState(ptr); 513 } 514 515 // Returns PRESENT/ABSENT/INVALID for a given handle value. 516 HandleState GetHandleState(zx_handle_t p) const { 517 return derived()->GetHandleState(p); 518 } 519 520 // If required: mutate a pointer to the dual representation. 521 template <class T2, class T1> 522 void UpdatePointer(T2 p, T1 v) { 523 derived()->UpdatePointer(p, v); 524 } 525 526 // Returns true when a handle was claimed, and false when the 527 // handles are exhausted. 528 template <class ZxHandleTPointer> 529 bool ClaimHandle(ZxHandleTPointer out_handle) { 530 if (handle_idx_ == num_handles()) { 531 derived()->UnclaimedHandle(out_handle); 532 return false; 533 } 534 derived()->ClaimedHandle(out_handle, handle_idx_); 535 ++handle_idx_; 536 return true; 537 } 538 539 // Returns true when the buffer space is claimed, and false when 540 // the requested claim is too large for bytes_. 541 bool ClaimOutOfLineStorage(uint32_t size, const void* storage, uint32_t* out_offset) { 542 if (!derived()->ValidateOutOfLineStorageClaim(storage, &bytes()[out_of_line_offset_])) { 543 return false; 544 } 545 546 // We have to manually maintain alignment here. For example, a pointer 547 // to a struct that is 4 bytes still needs to advance the next 548 // out-of-line offset by 8 to maintain the aligned-to-FIDL_ALIGNMENT 549 // property. 550 static constexpr uint32_t mask = FIDL_ALIGNMENT - 1; 551 uint32_t offset = out_of_line_offset_; 552 if (add_overflow(offset, size, &offset) || 553 add_overflow(offset, mask, &offset)) { 554 return false; 555 } 556 offset &= ~mask; 557 558 if (offset > num_bytes()) { 559 return false; 560 } 561 *out_offset = out_of_line_offset_; 562 out_of_line_offset_ = offset; 563 return true; 564 } 565 566 uint32_t TypeSize(const fidl_type_t* type) { 567 switch (type->type_tag) { 568 case fidl::kFidlTypeStructPointer: 569 case fidl::kFidlTypeTablePointer: 570 case fidl::kFidlTypeUnionPointer: 571 return sizeof(uint64_t); 572 case fidl::kFidlTypeHandle: 573 return sizeof(zx_handle_t); 574 case fidl::kFidlTypeStruct: 575 return type->coded_struct.size; 576 case fidl::kFidlTypeTable: 577 return sizeof(fidl_vector_t); 578 case fidl::kFidlTypeUnion: 579 return type->coded_union.size; 580 case fidl::kFidlTypeString: 581 return sizeof(fidl_string_t); 582 case fidl::kFidlTypeArray: 583 return type->coded_array.array_size; 584 case fidl::kFidlTypeVector: 585 return sizeof(fidl_vector_t); 586 } 587 abort(); 588 return 0; 589 } 590 591 // Functions that manipulate the decoding stack frames. 592 struct Frame { 593 Frame(const fidl_type_t* fidl_type, uint32_t offset) 594 : offset(offset) { 595 switch (fidl_type->type_tag) { 596 case fidl::kFidlTypeStruct: 597 state = kStateStruct; 598 struct_state.fields = fidl_type->coded_struct.fields; 599 struct_state.field_count = fidl_type->coded_struct.field_count; 600 break; 601 case fidl::kFidlTypeStructPointer: 602 state = kStateStructPointer; 603 struct_pointer_state.struct_type = fidl_type->coded_struct_pointer.struct_type; 604 break; 605 case fidl::kFidlTypeTable: 606 state = kStateTable; 607 table_state.fields = fidl_type->coded_table.fields; 608 table_state.field_count = fidl_type->coded_table.field_count; 609 table_state.present_count = 0; 610 break; 611 case fidl::kFidlTypeTablePointer: 612 state = kStateTablePointer; 613 table_pointer_state.table_type = fidl_type->coded_table_pointer.table_type; 614 break; 615 case fidl::kFidlTypeUnion: 616 state = kStateUnion; 617 union_state.types = fidl_type->coded_union.types; 618 union_state.type_count = fidl_type->coded_union.type_count; 619 union_state.data_offset = fidl_type->coded_union.data_offset; 620 break; 621 case fidl::kFidlTypeUnionPointer: 622 state = kStateUnionPointer; 623 union_pointer_state.union_type = fidl_type->coded_union_pointer.union_type; 624 break; 625 case fidl::kFidlTypeArray: 626 state = kStateArray; 627 array_state.element = fidl_type->coded_array.element; 628 array_state.array_size = fidl_type->coded_array.array_size; 629 array_state.element_size = fidl_type->coded_array.element_size; 630 break; 631 case fidl::kFidlTypeString: 632 state = kStateString; 633 string_state.max_size = fidl_type->coded_string.max_size; 634 string_state.nullable = fidl_type->coded_string.nullable; 635 break; 636 case fidl::kFidlTypeHandle: 637 state = kStateHandle; 638 handle_state.nullable = fidl_type->coded_handle.nullable; 639 break; 640 case fidl::kFidlTypeVector: 641 state = kStateVector; 642 vector_state.element = fidl_type->coded_vector.element; 643 vector_state.max_count = fidl_type->coded_vector.max_count; 644 vector_state.element_size = fidl_type->coded_vector.element_size; 645 vector_state.nullable = fidl_type->coded_vector.nullable; 646 break; 647 } 648 } 649 650 Frame(const fidl::FidlCodedStruct* coded_struct, uint32_t offset) 651 : offset(offset) { 652 state = kStateStruct; 653 struct_state.fields = coded_struct->fields; 654 struct_state.field_count = coded_struct->field_count; 655 } 656 657 Frame(const fidl::FidlCodedTable* coded_table, uint32_t offset) 658 : offset(offset) { 659 state = kStateStruct; 660 table_state.fields = coded_table->fields; 661 table_state.field_count = coded_table->field_count; 662 } 663 664 Frame(const fidl::FidlCodedUnion* coded_union, uint32_t offset) 665 : offset(offset) { 666 state = kStateUnion; 667 union_state.types = coded_union->types; 668 union_state.type_count = coded_union->type_count; 669 union_state.data_offset = coded_union->data_offset; 670 } 671 672 Frame(const fidl_type_t* element, uint32_t array_size, uint32_t element_size, 673 uint32_t offset) 674 : offset(offset) { 675 state = kStateArray; 676 array_state.element = element; 677 array_state.array_size = array_size; 678 array_state.element_size = element_size; 679 } 680 681 // The default constructor does nothing when initializing the stack of frames. 682 Frame() {} 683 684 static Frame DoneSentinel() { 685 Frame frame; 686 frame.state = kStateDone; 687 return frame; 688 } 689 690 uint32_t NextStructField() { 691 ZX_DEBUG_ASSERT(state == kStateStruct); 692 693 uint32_t current = field; 694 field += 1; 695 return current; 696 } 697 698 uint32_t NextArrayOffset() { 699 ZX_DEBUG_ASSERT(state == kStateArray); 700 701 uint32_t current = field; 702 field += array_state.element_size; 703 return current; 704 } 705 706 enum : int { 707 kStateStruct, 708 kStateStructPointer, 709 kStateTable, 710 kStateTablePointer, 711 kStateUnion, 712 kStateUnionPointer, 713 kStateArray, 714 kStateString, 715 kStateHandle, 716 kStateVector, 717 718 kStateDone, 719 } state; 720 // A byte offset into bytes_; 721 uint32_t offset; 722 723 // This is a subset of the information recorded in the 724 // fidl_type structures needed for decoding state. For 725 // example, struct sizes do not need to be present here. 726 union { 727 struct { 728 const fidl::FidlField* fields; 729 uint32_t field_count; 730 } struct_state; 731 struct { 732 const fidl::FidlCodedStruct* struct_type; 733 } struct_pointer_state; 734 struct { 735 const fidl::FidlTableField* fields; 736 uint32_t known_index; 737 uint32_t field_count; 738 uint32_t present_count; 739 uint32_t end_offset; 740 uint32_t end_handle; 741 } table_state; 742 struct { 743 const fidl::FidlCodedTable* table_type; 744 } table_pointer_state; 745 struct { 746 const fidl_type_t* const* types; 747 uint32_t type_count; 748 uint32_t data_offset; 749 } union_state; 750 struct { 751 const fidl::FidlCodedUnion* union_type; 752 } union_pointer_state; 753 struct { 754 const fidl_type_t* element; 755 uint32_t array_size; 756 uint32_t element_size; 757 } array_state; 758 struct { 759 uint32_t max_size; 760 bool nullable; 761 } string_state; 762 struct { 763 bool nullable; 764 } handle_state; 765 struct { 766 const fidl_type* element; 767 uint32_t max_count; 768 uint32_t element_size; 769 bool nullable; 770 } vector_state; 771 }; 772 773 uint32_t field = 0u; 774 }; 775 776 // Returns true on success and false on recursion overflow. 777 bool Push(Frame frame) { 778 if (depth_ == FIDL_RECURSION_DEPTH) { 779 return false; 780 } 781 decoding_frames_[depth_] = frame; 782 ++depth_; 783 return true; 784 } 785 786 void Pop() { 787 ZX_DEBUG_ASSERT(depth_ != 0u); 788 --depth_; 789 } 790 791 Frame* Peek() { 792 ZX_DEBUG_ASSERT(depth_ != 0u); 793 return &decoding_frames_[depth_ - 1]; 794 } 795 796 // Message state passed in to the constructor. 797 const fidl_type_t* const type_; 798 799 // Internal state. 800 uint32_t handle_idx_ = 0u; 801 uint32_t out_of_line_offset_ = 0u; 802 803 // Decoding stack state. 804 uint32_t depth_ = 0u; 805 Frame decoding_frames_[FIDL_RECURSION_DEPTH]; 806 }; 807 808 } // namespace internal 809 } // namespace fidl 810