| 471 | } |
| 472 | |
| 473 | Status ValidateLayout(const DataType& type) { |
| 474 | // Check the data layout conforms to the spec |
| 475 | const auto layout = type.layout(); |
| 476 | |
| 477 | if (data.length < 0) { |
| 478 | return Status::Invalid("Array length is negative"); |
| 479 | } |
| 480 | |
| 481 | if (layout.variadic_spec) { |
| 482 | if (data.buffers.size() < layout.buffers.size()) { |
| 483 | return Status::Invalid("Expected at least ", layout.buffers.size(), |
| 484 | " buffers in array of type ", type.ToString(), ", got ", |
| 485 | data.buffers.size()); |
| 486 | } |
| 487 | } else if (data.buffers.size() != layout.buffers.size()) { |
| 488 | return Status::Invalid("Expected ", layout.buffers.size(), |
| 489 | " buffers in array of type ", type.ToString(), ", got ", |
| 490 | data.buffers.size()); |
| 491 | } |
| 492 | |
| 493 | // This check is required to avoid addition overflow below |
| 494 | int64_t length_plus_offset = -1; |
| 495 | if (AddWithOverflow(data.length, data.offset, &length_plus_offset)) { |
| 496 | return Status::Invalid("Array of type ", type.ToString(), |
| 497 | " has impossibly large length and offset"); |
| 498 | } |
| 499 | |
| 500 | for (int i = 0; i < static_cast<int>(data.buffers.size()); ++i) { |
| 501 | const auto& buffer = data.buffers[i]; |
| 502 | const auto& spec = i < static_cast<int>(layout.buffers.size()) |
| 503 | ? layout.buffers[i] |
| 504 | : *layout.variadic_spec; |
| 505 | |
| 506 | if (buffer == nullptr) { |
| 507 | continue; |
| 508 | } |
| 509 | int64_t min_buffer_size = 0; |
| 510 | switch (spec.kind) { |
| 511 | case DataTypeLayout::BITMAP: |
| 512 | // If length == 0, buffer size can be 0 regardless of offset |
| 513 | if (data.length > 0) { |
| 514 | min_buffer_size = bit_util::BytesForBits(length_plus_offset); |
| 515 | } |
| 516 | break; |
| 517 | case DataTypeLayout::FIXED_WIDTH: |
| 518 | if (data.length > 0 && MultiplyWithOverflow(length_plus_offset, spec.byte_width, |
| 519 | &min_buffer_size)) { |
| 520 | return Status::Invalid("Array of type ", type.ToString(), |
| 521 | " has impossibly large length and offset"); |
| 522 | } |
| 523 | break; |
| 524 | case DataTypeLayout::ALWAYS_NULL: |
| 525 | // XXX Should we raise on non-null buffer? |
| 526 | continue; |
| 527 | default: |
| 528 | continue; |
| 529 | } |
| 530 | if (buffer->size() < min_buffer_size) { |
nothing calls this directly
no test coverage detected