Prevent Infinite Recursion on Cyclic Page Corruption#1301
Merged
Conversation
…ption During database startup/recovery or integrity checks on a corrupted redb file, B-tree tree-walking operations could get stuck in an infinite recursion, eventually exhausting the call stack and crashing the application. This was occurring in two main recursive operations: 1. RawBtree::verify_checksum_helper: Recursing down branch children to verify leaf checksums. 2. UntypedBtree::visit_pages_helper: Recursing down branch children to visit pages. If page corruption introduces cyclic pointers (e.g., a child page number points to an ancestor page), these functions would loop indefinitely. This commit resolves the issue by introducing cycle detection: - In RawBtree::verify_checksum_helper, we track the active DFS traversal path via a visited stack (Vec<PageNumber>). If a page has already been visited in the active path, it returns Ok(false) (checksum verification failure) instead of looping, allowing standard database repair/rollback to recover or fail gracefully. - In UntypedBtree::visit_pages_helper, we verify if a child page is already part of the active path (path.parents() or current page_number). If a cycle is detected, it returns a StorageError::Corrupted error. Added unit tests: - test_page_path_cycle_detection to verify loop detection on PagePaths. - test_verify_checksum_cycle_detection to verify loop detection on active verify stacks.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1301 +/- ##
==========================================
+ Coverage 90.22% 90.29% +0.06%
==========================================
Files 36 36
Lines 16457 16572 +115
==========================================
+ Hits 14848 14963 +115
Misses 1609 1609
🚀 New features to boost your workflow:
|
This adds a unit test 'test_cycle_detection_in_btree' which constructs corrupted cyclic branch nodes and verifies that RawBtree::verify_checksum_helper and UntypedBtree::visit_pages_helper correctly detect and handle cycles, ensuring high test coverage for the loop-prevention changes. Assisted-by: Antigravity
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.
During database startup/recovery or integrity checks on a corrupted
.redbfile, B-tree tree-walking operations could get stuck in an infinite recursion, eventually exhausting the call stack and crashing the application.This was occurring in two main recursive operations:
RawBtree::verify_checksum_helper: Recursing down branch children to verify leaf checksums.UntypedBtree::visit_pages_helper: Recursing down branch children to visit pages.If page corruption introduces cyclic pointers (e.g., a child page number points to an ancestor page), these functions would loop indefinitely.
This commit resolves the issue by introducing cycle detection:
RawBtree::verify_checksum_helper, we track the active DFS traversal path via a visited stack (Vec<PageNumber>). If a page has already been visited in the active path, it shotcircuits to returnOk(false)(checksum verification failure) instead of looping, allowing standard database repair/rollback to recover or fail gracefully.UntypedBtree::visit_pages_helper, we verify if a child page is already part of the active path (path.parents()orcurrent page_number). If a cycle is detected, it returns aStorageError::Corruptederror.Added unit tests:
test_page_path_cycle_detectionto verify loop detection on PagePaths.test_verify_checksum_cycle_detectionto verify loop detection on active verify stacks.I met this issue in the real project.