Repository navigation
fix(storage): refuse a sub-page file that is not a torn first write (#506) - #508
Merged
Merged
Conversation
…506) A file of 1..4095 bytes held no whole page, so open treated it as a new database and a read-write open re-initialised it. It now opens as new only when its bytes are zeros or a prefix of init_empty's generation-1 meta (the rule is_torn_initial_meta already applied to a full page 0); anything else is STG-045, read-write and read-only, with the file unchanged. StorageBackend gains partial_page() (bytes past the last whole page; None by default, forwarded by the mutex and fault-injection wrappers). The corrupt_file fuzzer no longer skips short files: they must fail to open or open empty. The #506 input and a meta-prefix truncation are corpus seeds. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_012wXxZguv7PgKQjMMH4yJ5h
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
This was referenced Oct 10, 2026
Merged
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.
Part of #506 (data-integrity; the issue stays open per the known-issues process).
Problem
A file of 1..4095 bytes holds no whole page, so
FileBackendreportedpage_count == 0and open took the new-database path. A read-write open then wrote a fresh empty database over it: a database cut below one page by an interrupted copy, or an unrelated file at the path, was silently replaced.Fix (option 2, decided on the issue)
StorageBackend::partial_page()returns the bytes past the last whole page (Noneby default;FileBackendreads them; the mutex and fault-injection wrappers forward it).select_metawithpage_count == 0: a tail is accepted as a new database only if it is zeros or a prefix ofMetaPage::empty(1).encode(), the same ruleis_torn_initial_metaapplies to a full page 0 (now shared asis_initial_meta_prefix). Anything else is the newSTG-045, read-write and read-only, with the file unchanged. A zero-length file is still a new database.Tests
tests/integrity_test.rs::sub_page_file_is_refused_unless_a_torn_first_write: cuts to 2222 and 20 bytes and foreign bytes giveSTG-045(rw and ro, file unchanged, no WAL); 8- and 40-byte meta prefixes and 300 zeros open, take a write and checkpoint.FileBackendunit test coverspartial_page.corrupt_filefuzzer: thelen < PAGE_SIZEskip is gone; a short file has to fail to open or open empty. New seeds: the A file shorter than one page opens as a new empty database (read-write re-initializes it) #506 reproducer, and a cut to an 8-byte meta prefix. Ran for 120 s locally, 5,192 runs, no findings.cargo test: 1372 passed, 9 ignored.cargo clippy --all-features -- -D warningsand the wasm32 browser clippy are clean.Docs:
ERROR_REFERENCE.md(STG-045),CHANGELOG.md,TEST_COVERAGE.md, test counts inCLAUDE.md/README.md.🤖 Generated with Claude Code
https://claude.ai/code/session_012wXxZguv7PgKQjMMH4yJ5h