Skip to content

Fix Windows read past EOF looping forever instead of erroring#1291

Merged
cberner merged 1 commit into
masterfrom
claude/windows-eof-read-hang-0q6f2e
Jul 5, 2026
Merged

Fix Windows read past EOF looping forever instead of erroring#1291
cberner merged 1 commit into
masterfrom
claude/windows-eof-read-hang-0q6f2e

Conversation

@cberner

@cberner cberner commented Jul 5, 2026

Copy link
Copy Markdown
Owner

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_read returns Ok(0) at end-of-file. The retry loop only advances offset/data_offset by the number of bytes read, so a zero-byte read leaves both counters unchanged and the while data_offset < out.len() loop never terminates and never errors.

The Unix (read_exact_at) and WASI backends both correctly return UnexpectedEof in this case, and the StorageBackend::read trait contract requires it: "If out.len() + offset exceeds the length of the storage an appropriate Error must 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 (in tests/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) return UnexpectedEof. It runs on every platform, including the windows-latest CI runner — before this fix that path would hang (surfacing as a CI timeout); after it, it passes.

Verification

  • cargo check / clippy --deny warnings for the x86_64-pc-windows-gnu target — the Windows-gated fix and test compile and lint clean (Linux builds skip this #[cfg(windows)] code entirely).
  • cargo fmt --check, Linux clippy --all-targets --all-features --deny warnings — clean.
  • Full cargo test --all-features — all pass.

A user-facing CHANGELOG.md entry is included under the unreleased 4.2.0 section.

🤖 Generated with Claude Code

https://claude.ai/code/session_01GeBFo3vreYtX9Z4BW2Nx2z


Generated by Claude Code

@codecov

codecov Bot commented Jul 5, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.19%. Comparing base (8e04e95) to head (51bcd12).

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     
Files with missing lines Coverage Δ
...rc/tree_store/page_store/file_backend/optimized.rs 77.27% <ø> (ø)

... and 1 file with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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
@cberner cberner force-pushed the claude/windows-eof-read-hang-0q6f2e branch from 2755f43 to 51bcd12 Compare July 5, 2026 13:27
@cberner cberner merged commit 6d131f9 into master Jul 5, 2026
8 checks passed
@cberner cberner deleted the claude/windows-eof-read-hang-0q6f2e branch July 5, 2026 14:24
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