Fix Windows read past EOF looping forever instead of erroring#1291
Merged
Conversation
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #1291 +/- ##
==========================================
+ Coverage 90.18% 90.19% +0.01%
==========================================
Files 36 36
Lines 16227 16227
==========================================
+ Hits 14634 14636 +2
+ Misses 1593 1591 -2
🚀 New features to boost your workflow:
|
On Windows, seek_read returns Ok(0) at end-of-file, so the read loop in the optimized FileBackend never advanced and never returned once a read extended past the end of the file. Opening a file truncated below the 320-byte header (e.g. an interrupted copy or restore), or a corrupt root page number pointing past EOF during repair, would hang instead of surfacing an error. Treat a zero-length read as UnexpectedEof, matching the Unix and WASI backends, so reading past the end of the file fails instead of spinning forever. Assisted-by: Claude Code Claude-Session: https://claude.ai/code/session_01GeBFo3vreYtX9Z4BW2Nx2z
2755f43 to
51bcd12
Compare
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.
Problem
On Windows, any read that extends past the end of the file hangs forever instead of returning an error. Opening a database file that has a valid magic number but is truncated below the 320-byte header (e.g. an interrupted copy or restore), or a corrupt root page number pointing past EOF during repair, spins indefinitely.
Root cause
In the Windows
FileBackend::read(src/tree_store/page_store/file_backend/optimized.rs),seek_readreturnsOk(0)at end-of-file. The retry loop only advancesoffset/data_offsetby the number of bytes read, so a zero-byte read leaves both counters unchanged and thewhile data_offset < out.len()loop never terminates and never errors.The Unix (
read_exact_at) and WASI backends both correctly returnUnexpectedEofin this case, and theStorageBackend::readtrait contract requires it: "Ifout.len()+offsetexceeds the length of the storage an appropriateErrormust be returned."CI and the fuzzer run on Linux with the in-memory backend, so this was never exercised.
Fix
Treat a zero-length read as
UnexpectedEof, mirroring the WASI backend's error kind and message, so reading past the end of the file fails instead of spinning.Test
read_past_eof_errors(intests/integration_tests.rs) writes an 8-byte file and asserts that both a read fully past EOF and a read that starts inside the file but extends past EOF (the truncated-header scenario) returnUnexpectedEof. It runs on every platform, including thewindows-latestCI runner — before this fix that path would hang (surfacing as a CI timeout); after it, it passes.Verification
cargo check/clippy --deny warningsfor thex86_64-pc-windows-gnutarget — the Windows-gated fix and test compile and lint clean (Linux builds skip this#[cfg(windows)]code entirely).cargo fmt --check, Linuxclippy --all-targets --all-features --deny warnings— clean.cargo test --all-features— all pass.A user-facing
CHANGELOG.mdentry is included under the unreleased 4.2.0 section.🤖 Generated with Claude Code
https://claude.ai/code/session_01GeBFo3vreYtX9Z4BW2Nx2z
Generated by Claude Code