| 2783 | } |
| 2784 | |
| 2785 | Status FuzzIpcFile(const uint8_t* data, int64_t size) { |
| 2786 | auto buffer = std::make_shared<Buffer>(data, size); |
| 2787 | |
| 2788 | Status final_status; |
| 2789 | |
| 2790 | struct IpcReadResult { |
| 2791 | std::shared_ptr<Schema> schema; |
| 2792 | std::vector<RecordBatchWithMetadata> batches = {}; |
| 2793 | }; |
| 2794 | |
| 2795 | // Try to read the IPC file as a stream to compare the results (differential fuzzing) |
| 2796 | auto do_stream_read = [&]() -> Result<IpcReadResult> { |
| 2797 | io::BufferReader buffer_reader(buffer); |
| 2798 | // Skip magic bytes at the beginning |
| 2799 | RETURN_NOT_OK( |
| 2800 | buffer_reader.Advance(bit_util::RoundUpToMultipleOf8(kArrowMagicBytes.length()))); |
| 2801 | ARROW_ASSIGN_OR_RAISE(auto batch_reader, RecordBatchStreamReader::Open( |
| 2802 | &buffer_reader, FuzzingOptions())); |
| 2803 | |
| 2804 | std::vector<RecordBatchWithMetadata> batches; |
| 2805 | while (true) { |
| 2806 | ARROW_ASSIGN_OR_RAISE(auto batch, batch_reader->ReadNext()); |
| 2807 | if (!batch.batch && !batch.custom_metadata) { |
| 2808 | // EOS |
| 2809 | break; |
| 2810 | } |
| 2811 | RETURN_NOT_OK(ValidateFuzzBatch(batch)); |
| 2812 | batches.push_back(batch); |
| 2813 | } |
| 2814 | return IpcReadResult{batch_reader->schema(), batches}; |
| 2815 | }; |
| 2816 | |
| 2817 | auto do_file_read = [&](bool pre_buffer) -> Result<IpcReadResult> { |
| 2818 | io::BufferReader buffer_reader(buffer); |
| 2819 | ARROW_ASSIGN_OR_RAISE(auto batch_reader, |
| 2820 | RecordBatchFileReader::Open(&buffer_reader, FuzzingOptions())); |
| 2821 | if (pre_buffer) { |
| 2822 | // Pre-buffer all record batches |
| 2823 | RETURN_NOT_OK(batch_reader->PreBufferMetadata(/*indices=*/{})); |
| 2824 | } |
| 2825 | |
| 2826 | IpcReadResult result = {.schema = batch_reader->schema()}; |
| 2827 | const int n_batches = batch_reader->num_record_batches(); |
| 2828 | // Delay error return until the end, as we want to access all record batches |
| 2829 | Status st; |
| 2830 | for (int i = 0; i < n_batches; ++i) { |
| 2831 | RecordBatchWithMetadata batch; |
| 2832 | st &= batch_reader->ReadRecordBatchWithCustomMetadata(i).Value(&batch); |
| 2833 | st &= ValidateFuzzBatch(batch); |
| 2834 | result.batches.push_back(batch); |
| 2835 | } |
| 2836 | RETURN_NOT_OK(st); |
| 2837 | return result; |
| 2838 | }; |
| 2839 | |
| 2840 | // Persistent read result for differential fuzzing. |
| 2841 | std::optional<IpcReadResult> maybe_read_result; |
| 2842 |
no test coverage detected