#1257·bbolt

`Tx.Check` can hang or dereference invalid pages when branch references are corrupt

Author: sina-amCreated Aug 14, 2026Updated Aug 14, 2026

Description

I was experimenting with the bbolt source code and intentionally corrupted database files when I noticed two cases where Tx.Check does not handle corrupt branch-page references safely.

I wrote two test cases that reproduce the problems:

  1. A branch page references an already visited page, forming a cycle.
  2. A branch page references a page ID equal to the database high-water mark.

Both tests currently fail.

Cyclic page reference

The reachability check detects that a page has multiple references, but the page traversal continues descending into it.

For example, a branch page might reference itself:

root page → root page

Or several pages might form a longer cycle:

A → B → C → A

In either case, the checker repeatedly follows the cycle. The goroutine running Tx.Check never finishes, leaving callers waiting indefinitely while ranging over the error channel.

Out-of-bounds branch reference

The recursive traversal dereferences branch page IDs before validating them against tx.meta.Pgid(). The second test sets a branch reference to the database high-water mark. This is invalid because valid page IDs must be below that value. Instead of returning a clear out of bounds error, the checker attempts to load the page and may report a recovered panic or another validation error. The page ID should be checked before it is dereferenced, using pageID >= hwm as the invalid boundary condition.

I also found #877: Check of corrupted file deadlocks, which looks related because it also reports Tx.Check hanging on a corrupted database. However, I’m not sure whether it has the same underlying cause.

I have a proposed fix along with two regression tests. Once it is open, I will link it here. Thanks!