Skip to content

fix(buffers): correct offset file id calculation in disk_v2 ledger#25539

Open
xfocus3 wants to merge 1 commit into
vectordotdev:masterfrom
xfocus3:fix/ledger-offset-file-id-25440
Open

fix(buffers): correct offset file id calculation in disk_v2 ledger#25539
xfocus3 wants to merge 1 commit into
vectordotdev:masterfrom
xfocus3:fix/ledger-offset-file-id-25440

Conversation

@xfocus3
Copy link
Copy Markdown

@xfocus3 xfocus3 commented May 30, 2026

Summary

Closes #25440.

get_offset_reader_file_id in the disk_v2 ledger computed the offset file id with u16 arithmetic:

self.get_current_reader_file_id().wrapping_add(offset) % MAX_FILE_ID

In production MAX_FILE_ID == u16::MAX (65535). When current + offset exceeds u16::MAX, the wrapping_add wraps at 65536 before the modulo by 65535, so distinct offsets near the boundary resolve to the same file id:

current = 65534, offset = 1 -> 65534.wrapping_add(1) % 65535 = 65535 % 65535 = 0   (correct)
current = 65534, offset = 2 -> 65534.wrapping_add(2) % 65535 = 0     % 65535 = 0   (wrong, should be 1)

This is also a likely root cause of #19759.

Fix

Perform the addition in u32 so the wrap occurs at MAX_FILE_ID as intended, then convert back to u16. The arithmetic is factored into a small helper (offset_file_id / offset_file_id_with_max) so it can be unit-tested directly (the ArchivedLedgerState method is otherwise hard to construct in a test).

How did you test this PR?

  • Added unit tests in ledger.rs:
    • offset_file_id_wraps_at_max — basic and wrap-around behavior.
    • offset_file_id_does_not_wrap_u16_before_modulo — exercises the u16::MAX boundary that triggered the bug (the test-only MAX_FILE_ID = 6 can't reach it, so the helper is tested with u16::MAX explicitly).
  • cargo test -p vector-buffers ledger → 4 passed.
  • cargo clippy -p vector-buffers --all-targets -- -D warnings and cargo fmt --check pass.

`get_offset_reader_file_id` computed `current.wrapping_add(offset) % MAX_FILE_ID`
in `u16`. When `MAX_FILE_ID` is `u16::MAX`, `current + offset` could wrap at
`u16::MAX + 1` before the modulo was applied, so distinct offsets near the
boundary collapsed to the same file id (e.g. current=65534 returned 0 for both
offset=1 and offset=2).

Perform the arithmetic in `u32` so the wrap happens at `MAX_FILE_ID` as intended.

Closes vectordotdev#25440
@xfocus3 xfocus3 requested a review from a team as a code owner May 30, 2026 15:52
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.

get_offset_reader_file_id is incorrect in ledger.rs

1 participant