Fix EliasFanoVec::rank returning out-of-range index for last element of large bucket#41
Merged
Cydhra merged 4 commits intoApr 17, 2026
Conversation
`search_element_in_block::<INDEX=true, UPWARD=true>`'s binary-search fallback sets `cursor = final_bound + direction`, but `final_bound` is an ABSOLUTE position in `lower_vec` while the subsequent fallthrough return `start_index_lower + cursor` treats `cursor` as RELATIVE. That double-counts `start_index_lower`, so `rank(v)` can return a value `>= len()` for a `v` that is actually in the vec. Trigger: the query equals the last element of an EF upper-bucket of size > BIN_SEARCH_THRESHOLD (= 4). Found via property testing; a minimal 14-element case is pinned as `test_rank_last_element_of_large_bucket`. Downstream, this bogus rank fed into a parallel EF vec's `get_unchecked` caused an OOB panic at `bit_vec/mod.rs:1187` in production. Fix: subtract `start_index_lower` when reassigning `cursor`, so the fallthrough return still yields the correct absolute index.
85d0f38 to
6fea488
Compare
Contributor
Author
|
Thanks, for merging fix so quickly! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
EliasFanoVec::rank(v)can return a value>= len()for a valuevthat is actually present in the vector, whenvis the last element of an EF upper-bucket whose size exceedsBIN_SEARCH_THRESHOLD(= 4).The bug is a single-line off-by-
start_index_lowerin the binary-search fallback ofsearch_element_in_block::<INDEX=true, UPWARD=true>atelias_fano/mod.rs:386:final_boundis an absolute index intolower_vec, but the fallthrough return addsstart_index_lowertocursor, double-counting it.Discovery
Found via property testing in a downstream crate that stores two parallel
EliasFanoVecs (term IDs and a per-term auxiliary value) and looks up the auxiliary viavec_b.get_unchecked(vec_a.rank(found)). For certain inputs, the bogus rank exceedsvec_b.len()and causes an out-of-bounds panic atbit_vec/mod.rs:1187(get_bits_unchecked'sdata[pos / WORD_SIZE]).A minimal counterexample (shrunk from 368 → 14 elements) is pinned as
test_rank_last_element_of_large_bucket. For the 14-element vector, indices 5..9 all fall into upper-bucket 4;rank(term_at_idx_9)returns14(= len) before the fix and9after.Fix
Subtract
start_index_lowerfromcursorwhen reassigning it in the fallthrough path so the final return remains correct:Verification
test_rank_last_element_of_large_bucket(fails before, passes after).cargo testandcargo test --release).Notes
Only
search_element_in_block's INDEX=true fallthrough branch is affected.successor,predecessor, andget_unchecked— andrankfor inputs whose bucket size is ≤BIN_SEARCH_THRESHOLD— are unaffected. No public API changes.