dolthub / dolthub/doltlite

PRAGMA integrity_check cannot detect extra index entries: aCnt is hardcoded to zero

Closed Beginner friendly
#2,911 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C
Stars
268
Forks
18
Avg merge
2h 26m
Merged PRs (30d)
454

Description

Found in a full-repo review at `0ba280f06f`.

`PRAGMA integrity_check`'s "wrong # of entries in index" arm cannot fire on a DoltLite-format database. It compares two VDBE registers that are both always zero, so an index holding entries with no corresponding table row is reported as `ok`.

## Cause

`pragma.c` fills registers 8.. from `OP_IntegrityCk` and then compares the index count against the table count (`src/pragma.c:1806-1834`):

```c
sqlite3VdbeLoadString(v, 2, "wrong # of entries in index ");
...
addr = sqlite3VdbeAddOp3(v, OP_Eq, 8+cnt, 0, 8+iTab);
```

Stock's `sqlite3BtreeIntegrityCheck` writes a real per-tree row count into `aCnt` (`src/btree.c:11389`, `sqlite3MemSetArrayInt64(aCnt, i, sCheck.nRow)`). The prolly implementation writes zero into every slot (`src/prolly_btree.c`, in `sqlite3BtreeIntegrityCheck`):

```c
if( aCnt ){
sqlite3VdbeMemSetInt64(&aCnt[i], 0);
}
```

so every comparison is `0 == 0`.

The stub dates to `293ab76455` (2026-03-16), whose message says it populated `aCnt` "to prevent crash when pragma reads uninitialized row counts". It was a crash fix that was never completed, and it has been silently disabling this check for the life of the project.

The rest of `integrity_check` is unaffected — the row-by-row block is plain VDBE over cursors, so missing index entries, non-unique entries, NULL-in-NOT-NULL, CHECK and STRICT violations are all still detected. Only the reverse direction, extra/orphan index entries, is invisible.

## Proof

Patched a scratch build to fill `aCnt` from the existing `countTreeEntries`, plus an env-gated `+1` on one tree to simulate one orphan entry:

```
root 0 : patched => wrong # of entries in index wb | master => ok
root 1 : patched => wrong # of entries in index wb | master => ok
root 2 : patched => wrong # of entries in index ub | master => ok
root 3 : patched => wrong # of entries in index ub | master => ok
root 4 : patched => wrong # of entries in index iv | master => ok
root 5 : patched => wrong # of entries in index iv | master => ok
```

For contrast, stock on a deliberately corrupted file reports the same class correctly: `wrong # of entries in index i1`.

No false positives on healthy databases across INTEGER PK, TEXT PK, WITHOUT ROWID composite PK, and unique + non-unique secondary indexes.

## Cost of the fix: none

`countTreeEntries` (`src/prolly_btree_cursor_count.c:5`) already exists and delegates to `prollySubtreeCount`, which reads the count from the root node header — O(1). Measured `PRAGMA integrity_check` on 500k rows plus an index: **0.31 s on master, 0.31 s patched.**

## Why it matters

`integrity_check` is the structural oracle this project leans on hardest: **1,460 call sites across 330 test files** (271 `.test`, 40 `.sh`, 17 `.c`, 2 `.py`), including the invariant check in the stateful VC fuzzer. Orphan index entries are exactly the defect shape of #2864 (`CREATE INDEX` indexing past the end of the mutmap), #2489, #2632 and #2644 — four index-corruption bugs in three weeks, every one of them found by a human rather than by this check.

## Fix

Fill `aCnt[i]` from `countTreeEntries(p, aRoot[i], &nRow)` instead of zero.

Contributor guide

No contributing guide indexed for this repository

Research direction

Read the sqlite3BtreeIntegrityCheck implementation in src/prolly_btree.c, the countTreeEntries helper in src/prolly_btree_cursor_count.c, and the aCnt consumer in src/pragma.c:1806-1834. Run existing PRAGMA integrity_check coverage and verify that healthy databases remain clean while an orphan index entry reports “wrong # of entries in index” instead of “ok”.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, sqlite
Domain
database
Issue type
Bug
Difficulty
2/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
78/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.