This is an automated email from the ASF dual-hosted git repository.
Jefffrey pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-rs.git
The following commit(s) were added to refs/heads/main by this push:
new b06b9c12c1 fix(arrow-ipc): return an error for a DictionaryBatch
without its data (#11020)
b06b9c12c1 is described below
commit b06b9c12c17dca4f575c9c3e5a091fdb9412bab7
Author: Marco Bonamente <[email protected]>
AuthorDate: Wed Sep 9 02:19:46 2026 +0200
fix(arrow-ipc): return an error for a DictionaryBatch without its data
(#11020)
# Which issue does this PR close?
Closes #11019.
# Rationale for this change
`DictionaryBatch.data` is optional in the flatbuffer grammar and
required by the format. `get_dictionary_values` opened it with `unwrap`,
so a file that omits it panicked instead of producing an `ArrowError`.
This is the same class of field, in the same file, that the footer's
custom metadata was just fixed for:
```rust
let (Some(key), Some(value)) = (kv.key(), kv.value()) else {
return Err(ArrowError::ParseError(
"Custom metadata in the IPC footer is missing a key or a
value".to_string(),
));
};
```
The patch uses that shape. The proposal is essentially "finish the
round".
A panic matters more than usual on this path: under `libfuzzer-sys` a
caught panic still becomes `abort()` before unwinding, so a fuzz target
reading untrusted IPC goes into quarantine rather than reporting a
rejected input.
# What changes are included in this PR?
One `let ... else` in `get_dictionary_values`, plus a regression test.
Measured before and after on `main`: the fixture panics without the
change and returns `Parser error: Dictionary batch is missing its data`
with it. `cargo test -p arrow-ipc` passes — 132, 7 and 11.
# Are these changes tested?
Yes. The fixture is the original 2169-byte input from the fuzzing corpus
of [plenora-IO-tools](https://github.com/PlenoraETL/plenora-IO-tools),
not a reduced one, added under `arrow-ipc/test/data/`.
# Are there any user-facing changes?
A file that used to panic now returns an `ArrowError::ParseError`. No
API change.
Co-authored-by: PlenoraETL <[email protected]>
---
arrow-ipc/src/reader.rs | 51 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 50 insertions(+), 1 deletion(-)
diff --git a/arrow-ipc/src/reader.rs b/arrow-ipc/src/reader.rs
index 6c0a6749d2..52a026863b 100644
--- a/arrow-ipc/src/reader.rs
+++ b/arrow-ipc/src/reader.rs
@@ -923,9 +923,14 @@ fn get_dictionary_values(
let value = value_type.as_ref().clone();
let schema = Schema::new(vec![Field::new("", value, true)]);
// Read a single column
+ let Some(data) = batch.data() else {
+ return Err(ArrowError::ParseError(
+ "Dictionary batch is missing its data".to_string(),
+ ));
+ };
let record_batch = RecordBatchDecoder::try_new(
buf,
- batch.data().unwrap(),
+ data,
Arc::new(schema),
dictionaries_by_id,
metadata,
@@ -2197,6 +2202,50 @@ mod tests {
);
}
+ #[test]
+ fn test_invalid_dictionary_batch_without_data() {
+ use crate::r#gen::Message::*;
+ use flatbuffers::FlatBufferBuilder;
+
+ let schema = Schema::new(vec![Field::new(
+ "col",
+ DataType::Dictionary(Box::new(DataType::Int8),
Box::new(DataType::Utf8)),
+ true,
+ )]);
+
+ // DictionaryBatch.data is optional in the flatbuffer grammar and
+ // required by the format
+ let mut fbb = FlatBufferBuilder::new();
+ let batch_offset = DictionaryBatch::create(
+ &mut fbb,
+ &DictionaryBatchArgs {
+ id: 0,
+ data: None,
+ isDelta: false,
+ },
+ );
+ fbb.finish_minimal(batch_offset);
+ let batch_bytes = fbb.finished_data().to_vec();
+ let batch =
flatbuffers::root::<DictionaryBatch>(&batch_bytes).unwrap();
+
+ let data_buffer = Buffer::from(vec![0u8; 0]);
+ let mut dictionaries: HashMap<i64, ArrayRef> = HashMap::new();
+
+ let err = read_dictionary(
+ &data_buffer,
+ batch,
+ &schema,
+ &mut dictionaries,
+ &MetadataVersion::V5,
+ )
+ .unwrap_err();
+
+ assert_eq!(
+ err.to_string(),
+ "Parser error: Dictionary batch is missing its data"
+ );
+ }
+
#[test]
fn test_missing_buffer_metadata_error() {
use crate::r#gen::Message::*;