Skip to content

Fix binarySearch() convergence at page boundaries#159

Open
94xhn wants to merge 2 commits into
ubco-db:mainfrom
94xhn:fix-binarysearch-missing-return
Open

Fix binarySearch() convergence at page boundaries#159
94xhn wants to merge 2 commits into
ubco-db:mainfrom
94xhn:fix-binarysearch-missing-return

Conversation

@94xhn

@94xhn 94xhn commented Jul 17, 2026

Copy link
Copy Markdown

Problem

binarySearch() read the final candidate page and then exited the loop without returning a value. Its first correction still checked first >= last, which is not sufficient when the midpoint is already one boundary of a two-page range: for a key below both pages, pageId is 0 while first < last, so last = pageId - 1 wraps to UINT32_MAX and the search reads an unrelated page.

Fix

Always compare the loaded page first. When the key is below it, stop if pageId == first; when the key is above it, stop if pageId == last. Otherwise narrow the range as before.

A regression test builds two real data pages, queries a key below the minimum, wraps the real file interface to record reads, and verifies that the search returns -1 after reading only page 0. Before the final fix it read page 647.

Tests

  • Linux official test_embedDB: 8/8 pass
  • GCC 13 ASan/UBSan: 8/8 pass
  • MinGW GCC 8: 8/8 pass
  • -Werror=return-type compile check for embedDB.c

94xhn and others added 2 commits July 18, 2026 01:08
binarySearch() in src/embedDB/embedDB.c fell off the end of a
non-void function without returning on its normal termination path
(first >= last), which is control-reaches-end-of-non-void-function
UB per C11 6.9.1p12 and reproduces with -Wreturn-type.

The unconditional pre-check "if (first >= last) break;" exited the
loop before the buffered page min/max key was ever compared against
the target key, so the function returned an indeterminate value on
every normal binary-search convergence, not just a rare edge case.

embedDBGet() uses this return value directly to decide whether a
record exists, so an existing record could be misreported as missing
(false negative) or an out-of-range key falsely reported as found,
whenever the caller enables EMBEDDB_USE_BINARY_SEARCH.

Fix mirrors the sibling linearSearch() function in the same file:
move the "no more room to narrow" exit to after the compareKey
check on each branch, and make it an explicit return -1 instead of
an unconditional break with no trailing return.

Verified with a standalone extraction of the exact function: before
the fix, -Wall -Wextra -Wreturn-type reports control-reaches-end-of-
non-void-function at -O0 and -O2, and the garbage return value is
uncorrelated with actual key membership. After the fix, zero warnings
and an 8-case test matrix (single-page hit/miss, multi-page middle/
boundary hits, below-all/above-all misses) all pass at -O0 and -O2.
A converged interval check does not prevent pageId - 1 from underflowing when the midpoint is already the first page. Guard the actual midpoint boundaries and cover the two-page lower-key case with the real file interface.

Constraint: preserve the existing binary-search page selection API

Confidence: high

Scope-risk: narrow

Tested: Linux official test 8/8; GCC 13 ASan/UBSan 8/8; MinGW GCC 8 8/8

Not-tested: Arduino targets
@94xhn 94xhn changed the title Fix binarySearch() falling off the end without a return (UB) Fix binarySearch() convergence at page boundaries Jul 17, 2026
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