Skip to content

Add proptest fuzzing to parquet-variant and implement fixes for findings - #10352

Open
cetra3 wants to merge 3 commits into
apache:mainfrom
pydantic:proptest_fuzzing_and_fixes
Open

Add proptest fuzzing to parquet-variant and implement fixes for findings#10352
cetra3 wants to merge 3 commits into
apache:mainfrom
pydantic:proptest_fuzzing_and_fixes

Conversation

@cetra3

@cetra3 cetra3 commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Which issue does this PR close?

This PR is not tied to a single pre-existing issue; it fixes findings 1-6 in the table below,
all found while adding the proptest harness. The two remaining findings are out of scope here
and are tracked as follow-up issues:

Here's a list of bugs found:

# Defect Location Effect Status
1 Unsorted dictionary with an empty field name is rejected metadata.rs:317 Rejects valid data Fixed
2 Unsorted dictionary offsets not checked for UTF-8 character boundaries metadata.rs (same branch) Validated, then panics on index/iter Fixed
3 Duplicate field names in an object are accepted object.rs:270 Accepts invalid data Fixed
4 decode_date overflows on large day counts decoder.rs:281 Panics inside try_new Fixed
5 decode_uuid indexes raw on a truncated payload decoder.rs:347 Panics inside try_new Fixed
6 Validation recurses without a depth limit list.rs:234, object.rs Process abort Fixed
7 shred_variant double-appends on duplicate field names shred_variant.rs:418-429 Panics in arrow-array Open (#10359)
8 PartialEq recurses without bound on shallow variants list.rs:313, object.rs Process abort Open (#10360)

Rationale for this change

This PR was raised after some bugs caught in production caused some failing jobs.

The original bug was empty field strings caused a weird offsets not monotonically increasing, but with the assistance of an agent, we expanded our search to use proptest to find some other similar cases.

What changes are included in this PR?

Adds a new proptest harness for parquet-variant and fixes

Are these changes tested?

Yes, most of these changes are driven by failing proptests and converted into smaller unit tests.

Are there any user-facing changes?

The only one that is probably worth mentioning, and maybe something we allow to be configured, is a max depth recursion constant was added.

@github-actions github-actions Bot added the parquet-variant parquet-variant* crates label Jul 16, 2026

@klion26 klion26 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@cetra3 Thanks for the fix, LGTM.
Does the item in the pr description with status open still needed after this pr, could you please help to file an issue to track them if needed?

Comment thread parquet-variant/tests/proptest.rs Outdated
use std::collections::HashSet;

/// The empty metadata dictionary.
const EMPTY_METADATA: &[u8] = &[1, 0, 0];

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can reuse the EMPTY_VARIANT_METADATA_BYTES in variant/metdata.rs

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done!

}
} else {
// The metadata dictionary can't guarantee uniqueness or sortedness, so we have to parse out the corresponding field names
// to check lexicographical order

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to update the doc here to respect the uniqueness?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

let mut current_offset = offsets.next().unwrap_or(0);
for next_offset in offsets {
value_buffer
.get(current_offset..next_offset)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious about the cause of the offset not land on UTF-8 character boundaries. is the data corrupt or the writer did not write the right data?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah this is to guard against corrupt data. I don't think there is a way to construct this shape of data with VariantBuilder but you can easily craft corrupted bytes that will hit a panic.

This is the same check as the other branch makes a handful of lines above, so nothing new here.

@sdf-jkl sdf-jkl left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @cetra3 LGTM with a nit

Comment thread parquet-variant/src/variant/metadata.rs
Comment thread parquet-variant/src/variant/object.rs
@cetra3
cetra3 force-pushed the proptest_fuzzing_and_fixes branch from 7cb043d to 546b20e Compare August 1, 2026 01:19

@Jefffrey Jefffrey left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

love to see proptests being used ❤️

should be good once conflicts are resolved, thanks for reviewing @klion26 & @sdf-jkl

return Err(ArrowError::InvalidArgumentError(
"offsets not monotonically increasing".to_string(),
));
// Slicing each dictionary value validates that offsets are in-bounds, non-decreasing,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small nit: original comment was correct in calling it monotonically increasing, as monotonically increasing allows either staying flat or going up. strict monotonically increasing is when its only going up (can't stay flat)

@Jefffrey

Copy link
Copy Markdown
Contributor

@cetra3 would you be able to merge up from main here

@cetra3
cetra3 force-pushed the proptest_fuzzing_and_fixes branch from 546b20e to 6f9372f Compare August 26, 2026 01:19
- Hoist shared `current_offset` initialization out of the sorted/unsorted
  branches in metadata validation (branches_sharing_code)
- Parenthesize shift in proptest metadata header construction (precedence_bits)

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug parquet-variant parquet-variant* crates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants