Skip to content

fix(db): heap page-item bounds check used btree/hash inp[] semantics - #67

Merged
gburd merged 1 commit into
masterfrom
fix/heap-dbret-okitem
Jul 28, 2026
Merged

fix(db): heap page-item bounds check used btree/hash inp[] semantics#67
gburd merged 1 commit into
masterfrom
fix/heap-dbret-okitem

Conversation

@gburd

@gburd gburd commented Jul 28, 2026

Copy link
Copy Markdown
Collaborator

Regression from PR #58 (malformed-file hardening). __db_ret_okitem gates every access-method cursor return through one bounds check, but it applied btree/hash inp[] semantics to HEAP pages, which use inp[] as an offset table with different rules:

  • valid heap slot indexes run up to HEAP_HIGHINDX, which can exceed NUM_ENT (deleted slots leave holes) → the generic indx >= NUM_ENT(h) reject was wrong for heap;
  • a deleted/empty heap slot has offset 0, and valid heap offsets need not fall after the inp[] array → the generic offset lower-bound reject was wrong.

Impact: db_dump (and any DB_NEXT scan) on a heap DB with a deleted non-last record returned DB_PAGE_NOTFOUND at end-of-scan instead of DB_NOTFOUND, so db_dump exited non-zero. Reproduced by test046/049/139 on the heap method — surfaced by the full-suite coverage run (see test/coverage/COVERAGE-TEST-TRIAGE.md, PR #66).

Fix: validate P_HEAP up front against HEAP_HIGHINDX + the heap record-header bounds, then return — don't fall through to the btree/hash generic checks. The btree/hash/recno hardening is unchanged.

Verification

How it was found

This is exactly the kind of latent bug deeper testing surfaces: the coverage run exercised the heap AM (previously untested), which hit the dump/load round-trip; triage isolated it to a clean-build heap failure; root-caused to my own #58 hardening being too btree-centric.

Regression from the malformed-file hardening (PR #58): __db_ret_okitem gated
every access-method cursor return through one bounds check, but it applied
btree/hash inp[] semantics to HEAP pages, which use inp[] as an offset table
with different rules:

- valid heap slot indexes run up to HEAP_HIGHINDX, which can exceed NUM_ENT
  (deleted slots leave holes), so the generic `indx >= NUM_ENT(h)` reject was
  wrong for heap;
- a deleted/empty heap slot has offset 0, and valid heap offsets don't have to
  fall after the inp[] array, so the generic offset lower-bound reject was wrong.

The result: db_dump (and any DB_NEXT scan) on a heap DB that had a non-last
record deleted returned DB_PAGE_NOTFOUND at end-of-scan instead of DB_NOTFOUND,
so db_dump exited non-zero -- reproduced by test046/049/139 on the heap method
(found by the full-suite coverage run; see test/coverage/COVERAGE-TEST-TRIAGE.md).

Fix: validate P_HEAP up front against HEAP_HIGHINDX and the heap record-header
bounds, then return -- do not fall through to the btree/hash generic checks.
The btree/hash/recno hardening is unchanged.

Verified: db_dump on the heap DB now succeeds; test046/049/139 pass on heap;
test001/003 pass on all five access methods + verify/salvage + logverify001; all
four fuzz crash reproducers (incl. the db_retcopy OOB the #58 guard protects)
still pass.
@gburd
gburd merged commit 6bd8f69 into master Jul 28, 2026
47 of 49 checks passed
@gburd
gburd deleted the fix/heap-dbret-okitem branch July 28, 2026 21:09
@github-actions

Copy link
Copy Markdown

Coccinelle convention checks

No new violations. ✅

Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in.
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/crypto/mersenne/mt19937db.c|return (ret);
rule_mutex_unbalanced|MUTEX_UNBALANCED|src/mp/mp_register.c|return (ret);

@github-actions

Copy link
Copy Markdown

ABI diff vs v5.3.31 (libabigail — authoritative)

Removed exported symbols (nm -D, _NNNN version suffix normalized)

None.


Advisory: libabigail/nm is the authoritative binary-ABI check; Coccinelle is complementary source-level early warning. See dist/cocci/README.md.

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