Skip to content

Bound the stripe statistics index in startNextStripe and getStripeStatistics - #33

Merged
PedroTadim merged 2 commits into
ClickHouse:ClickHouse/2.3.1from
groeneai:orc-missing-stripe-statistics
Oct 8, 2026
Merged

PedroTadim merged 2 commits into
ClickHouse:ClickHouse/2.3.1from
groeneai:orc-missing-stripe-statistics

Conversation

@groeneai

@groeneai groeneai commented Oct 6, 2026 •

Copy link
Copy Markdown

What changes were proposed in this pull request?

RowReaderImpl::startNextStripe evaluated the stripe statistics under if (sargsApplier_ && contents_->metadata) and read stripe_stats(currentStripe_) without checking the size. It now evaluates them only when stripe_stats_size() == stripes_size(); otherwise the stripes are read without stripe-level filtering, as for a file with no Metadata at all (row group indexes, bloom filters and dictionaries still apply). Entries are matched to stripes only by position, so a list of another length cannot be used: a too-small metadataLength keeps only the last entries, and a per-index check would apply them to the first stripes and drop matching rows.

ReaderImpl::getStripeStatistics has to return one specific entry, so before it reads the stripe footer it throws ParseError ("Malformed metadata: the file has N stripes but M stripe statistics") on a count mismatch, and InvalidArgument ("stripe index out of range") for an index past the last stripe.

main and fix-orc2-main have the same two unchecked reads; I can open the same change against main if you want it mirrored there too.

Why are the changes needed?

A Metadata section can parse into fewer entries than the footer has stripes: in ClickHouse/ClickHouse#124238 a corrupt PostScript metadataLength makes it parse as an empty message. Reading such a file with a search argument hit the protobuf bounds check on debug builds and crashed with SIGSEGV on release builds.

How was this patch tested?

In ClickHouse, ClickHouse/ClickHouse#124315 adds a stateless test with two crafted uncompressed files: 10 rows with an empty Metadata, and two 10-row stripes whose metadataLength keeps only the second stripe's entry. The current pin aborts in startNextStripe on both; this commit returns the same rows as with filter pushdown disabled, while a per-index check returns no rows for the second file. An indexHint query on the second file shows that the row group index still skips its second stripe. The issue's reproducer reads 1994 rows either way. A small harness calling getStripeStatistics throws the ParseError on the short files and InvalidArgument for index 1 of a one-stripe file, and returns the statistics of valid one- and two-stripe files.

Was this patch authored or co-authored using generative AI tooling?

Generated-by: Claude Opus 5.5

…tistics

A Metadata section with fewer entries than the footer has stripes (for
example after a corrupt PostScript metadataLength) made
RowReaderImpl::startNextStripe read stripe_stats(currentStripe_) out of
bounds when a search argument was set (protobuf bounds assert on debug,
SIGSEGV on release).

Entries are matched to stripes only by position, so a list of a different
length cannot be used at all: a too-small metadataLength keeps only the
LAST entries, which would otherwise be applied to the first stripes.
startNextStripe now evaluates stripe statistics only when there is one
entry per stripe; otherwise it reads the stripe without stripe-level
filtering (row group indexes, bloom filters and dictionaries still apply),
as for a file with no Metadata. getStripeStatistics throws ParseError on a
count mismatch and std::logic_error on an out-of-range stripe index.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Comment thread c++/src/Reader.cc Outdated
getStripeStatistics now rejects an out-of-range stripe index with
orc::InvalidArgument (a std::runtime_error). ClickHouse treats any
std::logic_error as a failed assertion and aborts in debug and sanitizer
builds, so a caller-supplied index must not be reported that way.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
groeneai added a commit to groeneai/ClickHouse that referenced this pull request Oct 8, 2026
Picks up ClickHouse/orc#33's second commit: getStripeStatistics reports an
out-of-range stripe index with orc::InvalidArgument, which ClickHouse does
not treat as a failed assertion.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@PedroTadim
PedroTadim merged commit 2195561 into ClickHouse:ClickHouse/2.3.1 Oct 8, 2026
1 check passed
@PedroTadim

Copy link
Copy Markdown
Member

@groeneai can you create the same PR, but to the main branch?

groeneai added a commit to groeneai/ClickHouse that referenced this pull request Oct 8, 2026
Re-pin contrib/orc from the PR head 2c69dbd6 to 21955610, the merge
commit of ClickHouse/orc#33 on ClickHouse/2.3.1. Both commits have the
same tree (8783f43c), so the library sources are unchanged.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@groeneai

groeneai commented Oct 8, 2026

Copy link
Copy Markdown
Author

Done: #34 (same change on main; the getStripeStatistics checks sit right after the metadata == nullptr check there, since main reads stripe_stats before the stripe footer).

PedroTadim pushed a commit that referenced this pull request Oct 8, 2026
…tistics

Same change as #33 on ClickHouse/2.3.1 (2195561).

A Metadata section with fewer entries than the footer has stripes (for
example after a corrupt PostScript metadataLength) made
RowReaderImpl::startNextStripe read stripe_stats(currentStripe_) out of
bounds when a search argument was set. Entries are matched to stripes only
by position, so startNextStripe now evaluates stripe statistics only when
there is one entry per stripe; otherwise it reads the stripe without
stripe-level filtering, as for a file with no Metadata.

getStripeStatistics throws ParseError on a count mismatch and
InvalidArgument on an out-of-range stripe index. On main it reads
stripe_stats(stripeIndex) before the stripe footer, so both checks go
right after the metadata check.

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

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants