Skip to content

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

Open
cetra3 wants to merge 2 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 2 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

parquet-variant parquet-variant* crates

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants