cryptus-neoxys opened a new pull request, #12189:
URL: https://github.com/apache/arrow-rs/pull/12189

   # Which issue does this PR close?
   
   - Closes #12129
   
   > Note for reviewers (duplicate-work check): the issue has no assignee. A 
search for PRs
   > referencing #12129 shows a single prior attempt, #12139, which a 
maintainer closed on
   > Nov 9, 2026 because its AI usage was not disclosed. This branch is an 
independent
   > implementation and discloses AI usage below, as CONTRIBUTING.md requires. 
If the
   > maintainer who closed #12139 prefers to wait until its author reopens it, 
this PR can
   > be closed and resubmitted later; the branch is here either way.
   
   # Rationale for this change
   
   A primitive column (for example `INT32`) whose data page claims 
`RLE_DICTIONARY`
   encoding while the column chunk has no dictionary page panics the reader:
   
   ```
   thread 'main' panicked at parquet/src/column/reader/decoder.rs:361:18:
   Decoder for dict should have been set
   ```
   
   The issue's reproducer writes a dictionary-encoded `Int32` column and 
mutates the
   dictionary page header's type from `DICTIONARY_PAGE` (2) to `INDEX_PAGE` 
(1). The page
   reader skips the page as an index page, the following data page still claims 
dictionary
   encoding, and `ColumnValueDecoderImpl::set_data` expects a dictionary 
decoder that was
   never installed. Because a truncated or otherwise malformed file can produce 
this state,
   any application reading untrusted Parquet files can be crashed.
   
   The byte-array readers already handle the equivalent case
   (`parquet/src/arrow/array_reader/byte_array.rs`, `missing dictionary page 
for column`),
   and empirically they return that error on every read attempt. This PR 
mirrors that
   handling for the generic primitive decoder.
   
   One detail beyond the one-line swap: with only `expect` replaced by 
`ok_or_else`, the
   arrow-level reproducer returns the expected error on the first poll and then 
panics on
   the second poll at `read()` (`current_encoding should be set`), because 
`read_new_page`
   claims the page's values before `set_data` runs and `current_encoding` is 
only written
   on success. The guards described below close that second panic so the 
primitive decoder
   behaves like the byte-array readers, which error on every attempt instead of 
panicking
   or ending iteration.
   
   # What changes are included in this PR?
   
   All in `parquet/src/column/reader/decoder.rs`, the primitive value decoder:
   
   - `set_data` returns `missing dictionary page for column` (the byte-array 
readers'
     message) instead of `expect`ing the dictionary decoder slot to be 
populated.
   - `set_data` clears `current_encoding` before configuring the new page, so a 
failed
     page cannot be retried with the previous page's decoder state.
   - `read` and `skip_values` return `the current data page failed to decode` 
when no data
     page has been decoded, so a retry after a failed page errors instead of 
panicking.
   
   Tests:
   
   - `parquet/src/file/serialized_reader.rs`:
     `dict_encoded_data_page_without_dictionary_page_errors` exercises the 
column reader
     with the issue's mutated header and asserts the first attempt and a retry 
both error.
   - `parquet/tests/arrow_reader/bad_data.rs`: 
`test_arrow_rs_gh_12129_missing_dictionary_page`
     generates the file in memory, mutates the header, and asserts through
     `ArrowReaderBuilder` that the first two polls return errors rather than 
panicking.
     Both regression tests panic at `decoder.rs:361` when the fix is reverted 
(verified by
     reapplying the pre-fix `expect` locally and running them).
   
   # Are these changes tested?
   
   Yes, by the two tests above plus the existing suites. Commands and results 
(rustc/cargo
   1.99.1, macOS aarch64):
   
   - `cargo test -p parquet`: all suites green, 0 failures: lib 1508 passed (1 
ignored),
     `tests/arrow_reader` 147 passed (1 ignored), `tests/arrow_writer` 114 
passed,
     `tests/encryption` 2 passed, `tests/ieee754_nan_interop` 2 passed,
     `tests/variant_integration` 80 passed (7 ignored), `tests/geospatial` 0 
(feature
     gated).
   - `cargo test -p parquet --test arrow_reader bad_data::`: 11 passed, 
including the new
     test.
   - `cargo test -p parquet --lib file::serialized_reader::tests`: 48 passed, 
including
     the new test.
   - `cargo clippy -p parquet --all-targets --all-features -- -D warnings`: 
clean.
   - `cargo fmt --all -- --check`: clean.
   - `typos --config typos.toml` on the three changed files: clean.
   
   Not run here: the full workspace suite (`cargo test --workspace`) and `cargo 
test
   -p arrow`; this PR only touches the parquet crate, and the affected crate 
was tested in
   full. Miri was not run (no unsafe changes).
   
   # Are there any significant user-facing changes?
   
   Behavior on malformed input changes: a dictionary-encoded data page without a
   dictionary page now returns `Err(ParquetError::General("missing dictionary 
page for
   column"))` instead of panicking. This matches the byte-array readers and is 
not a
   breaking API change.
   
   # AI usage disclosure
   
   This PR was implemented with AI assistance: an AI coding agent (OpenCode 
running the
   GLM model from Z.ai) produced the patch and tests under direction from the 
submitter.
   The submitter reviewed the diff in full, confirmed the reproducer from the 
issue panics
   before the fix and returns errors after it, and takes responsibility for the 
changes.
   This disclosure is included because a prior PR for the same issue (#12139) 
was closed
   for an undisclosed AI contribution.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to