Skip to content

fix: bulk shard decode must only engage for identity full reads - #256

Closed
d-v-b wants to merge 1 commit into
mainfrom
fix/bulk-shard-decode-identity-gate
Closed

fix: bulk shard decode must only engage for identity full reads#256
d-v-b wants to merge 1 commit into
mainfrom
fix/bulk-shard-decode-identity-gate

Conversation

@d-v-b

@d-v-b d-v-b commented Jul 29, 2026

Copy link
Copy Markdown
Owner

🤖 AI text below 🤖

Fixes the second critical from the PR zarr-developers#3885 audit, plus two hardening items in the same code. Only the opt-in FusedCodecPipeline reaches this path.

_decode_full_shard_bulk_if_uncompressed gated on sel_shape is None and indexer.shape == shard_spec.shape. OrthogonalIndexer — produced by plain arr[perm, :] and arr.oindex[...] — has no sel_shape, so on uncompressed, crc-free sharded arrays the bulk path fired for reordering and duplicate fancy-index reads and returned the shard in natural order: silent wrong data for multi-shard permutation reads and duplicate-index selections. (The earlier sel_shape gate only stopped vindex/CoordinateIndexer.)

The gate is now a structural identity-full-read predicate over the indexer's dim_indexers — every dimension must be a full SliceDimIndexer — deliberately NOT isinstance(indexer, BasicIndexer), since arr[:] produces an OrthogonalIndexer and a type gate would silently disable the fast path for the common full read. Spy-based engagement tests pin both directions: the bulk path still fires for full reads (single- and multi-shard) and never for permutation/duplicate/subset selections.

Also in this PR:

21 new/parametrized regression cases fail pre-fix; 533 passed post-fix on the verification suites; reviewer independently exercised multi-shard and edge-shard engagement scenarios live.

🤖 Generated with Claude Code

…x density check

The FusedCodecPipeline's vectorized whole-shard decode accepted any
indexer without `sel_shape` whose output shape matched the shard shape.
An OrthogonalIndexer from `arr[perm, :]` / `arr.oindex[...]` satisfies
that, so reordering or duplicating fancy-index reads on uncompressed,
crc-free sharded arrays silently returned the shard in natural order.
The bulk path now requires an identity full read: one whole-dimension,
step-1 slice per dimension (structural, not a BasicIndexer type check,
since `arr[:]` arrives as an OrthogonalIndexer).

Also:
- decline structured dtypes in the bulk path, which lacks the Struct
  byte-order branch of BytesCodec._decode_sync (latent until zarr-developers#3054 is
  fixed);
- `_ShardIndex.is_dense` now requires offsets to exactly tile the data
  section instead of merely being unique, so corrupt indexes with
  overlapping or out-of-range offsets (e.g. pointing into an
  index_location='start' index region) cannot be served as array data.

Assisted-by: ClaudeCode:claude-fable-5
@d-v-b
d-v-b force-pushed the fix/bulk-shard-decode-identity-gate branch from 2287a0b to 42241ba Compare July 29, 2026 14:32
@d-v-b d-v-b closed this Jul 30, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant