Skip to content

Stable 25.8 Backport of #93663 - Fix trash in TokenExtractor - #2608

Closed
VighneshPath wants to merge 3 commits into
Altinity:stable-25.8from
VighneshPath:backport/stable-25.8/93663
Closed

VighneshPath wants to merge 3 commits into
Altinity:stable-25.8from
VighneshPath:backport/stable-25.8/93663

Conversation

@VighneshPath

@VighneshPath VighneshPath commented Oct 19, 2026 •

Copy link
Copy Markdown

Backport of ClickHouse#93663.

The automatic cherry-pick to 25.8 (ClickHouse#93766) was closed because of conflicts, so I applied the same bounds checks by hand in NgramTokenExtractor::nextInString, NgramTokenExtractor::nextInStringLike and DefaultTokenExtractor::nextInStringLike.

If a string ends in a cut-off multibyte UTF-8 char, ngrambf_v1 reads a few bytes past the end of it. For the last row in a block that's uninitialized padding, so two replicas can build different skp_idx_*.idx files from the same parts. We hit this on a 25.8.16 cluster as a constant stream of CHECKSUM_DOESNT_MATCH / DataAfterMergeDiffersFromReplica on tables with ngrambf_v1 over truncated comments. The data files were identical; only the ngram .idx differed.

Repro: https://fiddle.clickhouse.com/5891f09a-5316-4504-9a42-1ff64b32c8f7 (25.8, different checksums), https://fiddle.clickhouse.com/04608712-7ad0-4b87-a8bc-5ed4663f5b71 (26.3, same).

Added test 05317_ngrambf_truncated_utf8_overrun, which fails without the fix.

Changelog category (leave one):

  • Critical Bug Fix (crash, data loss, RBAC)

Changelog entry (a user-readable short description of the changes that goes to CHANGELOG.md):

The usage of ngram_bf index on a non-UTF-8 data led to an uninitialized memory read, with values that could reside in the resulting index structure. (ClickHouse#93663 by @alexey-milovidov)

CI/CD Options

Exclude tests:

  • Fast test
  • Integration Tests
  • Stateless tests
  • Stateful tests
  • Unit tests
  • Performance tests
  • Aarch64 tests
  • All with ASAN
  • All with TSAN
  • All with MSAN
  • All with UBSAN
  • All with Coverage
  • All Regression
  • Disable CI Cache

Regression jobs to run:

  • Fast suites (mostly <1h)
  • Aggregate Functions (2h)
  • Alter (1.5h)
  • Benchmark (30m)
  • CAS (content-addressed storage; Antalya only)
  • ClickHouse Keeper (1h)
  • Iceberg (2h)
  • LDAP (1h)
  • OAuth (5m)
  • Parquet (1.5h)
  • RBAC (1.5h)
  • SSL Server (1h)
  • S3 (2h)
  • S3 Export (2h)
  • Swarms (30m)
  • Tiered Storage (2h)

alexey-milovidov and others added 3 commits October 16, 2026 18:02
`NgramTokenExtractor::nextInString` adds `UTF8::seqLength` of the lead byte
without clamping to the string length. A string that ends with a truncated
multibyte UTF-8 character makes the token extend past the end of the string,
so `ngrambf_v1` hashes bytes beyond it. For the last row of a block those
bytes are uninitialized column padding, so the index content becomes
nondeterministic. Replicas then build different `skp_idx_*.idx` files for
the same merge, which shows up as `CHECKSUM_DOESNT_MATCH` /
`DataAfterMergeDiffersFromReplica` and a re-fetch of the merged part.

Upstream cherry-pick to 25.8 (ClickHouse#93766)
was closed on conflicts. This applies the same bounds checks to the 25.8 code:
`NgramTokenExtractor::nextInString`, `NgramTokenExtractor::nextInStringLike`
and `DefaultTokenExtractor::nextInStringLike`. `SparseGramsTokenExtractor`
does not exist in this file in 25.8.

Original PR: ClickHouse#93663
Closes upstream issue: ClickHouse#92576

(cherry picked from commit f9fc3b2, conflicts resolved manually)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…8 tail

`05317_ngrambf_truncated_utf8_overrun` uses one row per granule, so the bytes after
the first string are the second row. Without the fix the n-gram `ab\xE4xx` lands in
the first granule's filter and `LIKE '%ab\xE4xx%'` reads `Granules: 1/2`; with the
fix both granules are skipped (`0/2`). Verified on this branch: fails without the
`NgramTokenExtractor::nextInString` change, passes with it.

`03784_msan_token_iterator` from upstream relies on `create_table_empty_primary_key_by_default`,
which the 25.8 test infrastructure does not set, so add `ENGINE = MergeTree ORDER BY ()`.

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

mkmkme commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

@blau-ai

@blau-ai

blau-ai commented Oct 22, 2026

Copy link
Copy Markdown
Collaborator

CI triage

Verdict: 2 failures, both infra flakes — neither is caused by this PR. All 6 amd builds, Fast test, every stateless shard that actually ran (incl. the amd_asan flaky check that re-runs changed tests), and all unit tests are green. No code change needed; just re-run the two red jobs.

1. Build (arm_release) — infra (artifact upload stalled)

The build itself compiled cleanly — ninja reached [14884/14884], sccache reported Compilation failures 0, and several artifacts uploaded fine (SHA256 digest of uploaded artifact is ...). The job then died on an upload, not a compile:

2026-10-19T09:59:14Z ##[error]Upload progress stalled.

This is a GitHub artifact/storage network hiccup during upload, unrelated to the ITokenExtractor.cpp change. (Note the arm_release build still runs even though the PR ticks "exclude aarch64/arm" — that box only skips arm tests.)
→ Next step: re-run the Build (arm_release) job. Safe to re-run.

2. Stateless tests (amd_asan, distributed plan, parallel, 2/2) — infra (docker pull timeout)

Job lasted only ~4 min and never started any test — it failed pulling the test image:

docker: Error response from daemon: Get "https://registry-1.docker.io/v2/altinityinfra/stateless-test/manifests/sha256:80ad94...": net/http: TLS handshake timeout.
ERROR: Job killed, exit code [125]

A Docker Hub TLS handshake timeout before any query ran. The sibling shard 1/2 passed, as did Stateless tests (amd_debug, parallel), so the test set itself is fine.
→ Next step: re-run the Stateless tests (amd_asan, distributed plan, parallel, 2/2) job. Safe to re-run.

PR health

The backport diff is small and well-contained (three bounds clamps in NgramTokenExtractor::nextInString, NgramTokenExtractor::nextInStringLike, DefaultTokenExtractor::nextInStringLike) plus two regression tests. The new 05317_ngrambf_truncated_utf8_overrun and 03784_msan_token_iterator ran green in the passing stateless shards and the amd_asan flaky check (which re-runs changed tests repeatedly) — good signal the fix and tests are stable. Once the two infra jobs are re-run, this should go fully green.

🤖 Triage by @blau-ai · evidence: run 39218448627

@mkmkme mkmkme changed the title Backport/stable 25.8/93663 Stable 25.8 Backport of #93663 - Fix trash in TokenExtractor Oct 22, 2026
@zvonand zvonand added 25.8 25.8 Altinity Stable backport Backport verified Approved for release and removed verified Approved for release labels Oct 22, 2026
@zvonand

zvonand commented Oct 22, 2026

Copy link
Copy Markdown
Member

@VighneshPath please, reopen this PR from Altinity's fork. seems like our community workflow is not yet fully functioning

@zvonand zvonand closed this Oct 25, 2026
@zvonand

zvonand commented Oct 25, 2026

Copy link
Copy Markdown
Member

closed in favor of #2672

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

Labels

25.8 25.8 Altinity Stable backport Backport

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants