Skip to content

reader: Fix bits_read sync on all seek variants#661

Open
PedroDeSanti wants to merge 4 commits into
sharksforarms:masterfrom
PedroDeSanti:fix/seek-bits-read-tracking
Open

reader: Fix bits_read sync on all seek variants#661
PedroDeSanti wants to merge 4 commits into
sharksforarms:masterfrom
PedroDeSanti:fix/seek-bits-read-tracking

Conversation

@PedroDeSanti

@PedroDeSanti PedroDeSanti commented May 13, 2026

Copy link
Copy Markdown

Closes #606.

Bug

Reader::seek updates bits_read only for some SeekFrom variants:

  • SeekFrom::Start(n) skips the update when n == 0
  • SeekFrom::Current(n) skips when n <= 0
  • SeekFrom::End(_) never updates it

After one of those seeks, the inner reader sits at the right byte position but bits_read keeps the old value. The generated from_bytes body then computes idx = bits_read / 8 and slices input.get(idx..) at the wrong offset. The result is either:

  • Err(Incomplete(NeedSize { bits: N })) even though the parse already succeeded, or
  • Ok(...) with a wrong consumed-byte count.

Fix

Drop the SeekFrom match and read the position back from the inner reader directly:

let new_pos = self.inner.seek(pos)?;
self.bits_read = usize::try_from(new_pos)
    .unwrap_or(usize::MAX)
    .saturating_mul(8);
Ok(new_pos)

Covers Start(0), negative Current, and any End the same way. The saturating conversion keeps bits_read correct on targets where usize is narrower than u64 and for streams larger than usize::MAX / 8 bytes.

Tests

New regression tests in tests/test_seek.rs:

  • test_seek_from_start_zero_rewind - round-trips a struct using seek_from_start = "0" after a forward seek (minimal repro of the bug).
  • test_seek_from_end_rewind - round-trips a struct using seek_from_end, the variant that was never updating bits_read before the fix.
  • test_seek_from_current_negative_rewind - round-trips a struct using negative seek_from_current (original scenario in Reader::seek doesn't rewind bits read, causing leftover slice error #606).
  • test_seek_error_preserves_bits_read - directly asserts bits_read is unchanged when the inner seek returns an error.

Repro

I put together a small repo with three scenarios from #606 showing upstream vs patched outputs side by side:

https://github.com/PedroDeSanti/deku-seek-bug-tests

Copilot AI review requested due to automatic review settings May 13, 2026 16:12

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot reviewed 2 out of 2 changed files in this pull request and generated 2 comments.


💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/test_seek.rs

let (_, ret_read) = SeekStartZero::from_bytes((&input, 0)).unwrap();
assert_eq!(ret_read, expected);
}

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

Comment thread src/reader.rs Outdated
self.inner.seek(pos)

let new_pos = self.inner.seek(pos)?;
self.bits_read = (new_pos as usize) * 8;

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done

@PedroDeSanti PedroDeSanti force-pushed the fix/seek-bits-read-tracking branch from 4f4f870 to c43a3c0 Compare May 18, 2026 22: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.

Reader::seek doesn't rewind bits read, causing leftover slice error

3 participants