test(faultinject): deepen malloc-failure sweep (M 506->947) — 1 new crash + 2 new OOM leaks - #90
Merged
Merged
Conversation
Extend the malloc-failure injection sweep workload beyond the basic open/put/get/cursor/txn flow to drive the warmer error paths functional tests miss: - secondary index: associate + get-by-secondary + pget - join cursor (DB->join) - bulk put/get (DB_MULTIPLE_KEY write buffer + cursor scan) - in-memory DB (NULL filename) - subdatabase open (named DB in a container file) - compaction (DB->compact with DB_FREE_SPACE) - DB->stat - 2PC prepare (txn->prepare then resolve) Baseline allocation count grows M = 506 -> 947 (+441 sites, ~87% more failure points swept). txn_recover is intentionally omitted: on a live in-process prepared txn it double-resolves and panics the region; the prepare path alone reaches the new 2PC alloc sites. Ignore build_asan/ (the ASan build tree the CI/local ASan pass creates).
…an CI workflow
Update README with the expanded-workload results: M = 947, 861 clean-error,
81 tolerated, 5 CRASH, 0 HANG, 0 DIRTY. Document the new engine bugs the
wider sweep surfaced (report only, not fixed here):
- Bug A (crash, K=490-493,497): NULL-deref in __db_cursor on the
hash-abort undo path (__ham_insdel_recover -> __db_cursor on a
half-built handle during __txn_abort at env teardown).
- Bug B (ASan leak): __db_create_internal err: path frees dbp+mpf but
not dbp->bt_internal / q_internal (the access-method private struct).
- Bug C (ASan leak): __db_join leaks the join cursor on its OOM path.
The four original bugs (PR #52) no longer reproduce on the current tree.
CI: the full plain-debug sweep (K=1..M, ~46s) stays the gate. The ASan
one-shot pass should sweep the full K=1..M range (~2min, ~0.13s/run) so it
reaches the new leaks/crashes past K=480 instead of stopping at 260. Agent
pushes lack `workflow` scope, so that workflow update is staged as
test/faultinject/faultinject.yml.workflow for a maintainer to sync into
.github/workflows/faultinject.yml (the installed file is left unchanged).
Coccinelle convention checksNo new violations. ✅ Resolved since baseline (2) -- update dist/cocci/baseline.txt to lock these in. |
ABI diff vs
|
This was referenced Jul 30, 2026
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.
What
Broadens the SQLite-style malloc-failure injection sweep (
test/faultinject/fi_sweep.c, from PR #49) so its workload reaches substantially more allocation sites, then re-runs the sweep under plain-debug and clang ASan.The old workload (open env + btree + hash, put/get/cursor/txn commit+abort, checkpoint) reached M = 506 alloc sites. It now also drives the warmer error paths functional tests miss:
associate+ get-by-secondary +pgetDB->joinDB_MULTIPLE_KEYwrite buffer +DB_MULTIPLE_KEYcursor scanDB->compactwithDB_FREE_SPACEDB->stattxn->preparethen resolveNew baseline: M = 947 (+441 sites, ~87% more failure points swept).
Results (deterministic, K = 1..947)
Plain-debug sweep: ~46s. ASan full one-shot sweep: ~2min. The four original bugs (PR #52) no longer reproduce on the current tree.
New OOM bugs found — report only, NOT fixed here (per harness policy)
Bug A — crash, K = 490, 491, 492, 493, 497 (plain-debug + ASan SEGV). NULL-deref on the hash-abort undo path, same stack for all five:
The wider workload leaves an aborted-hash txn to undo at env teardown; when an alloc on the undo path fails,
__ham_insdel_recoveropens a cursor on a dbp whose backing was never allocated. Repro:DB_FI_FAIL_AT=490 ./libtool --mode=execute ./fi_sweep --one.Bug B — ASan leak (
__db_create_internalOOM teardown).src/db/db_method.c:206frees onlydbp+dbp->mpf, neverdbp->bt_internal/q_internal(the access-method private struct from__bam_db_create/__qam_db_create), and sets*dbpp = NULLso the caller can't free it either. Repro:DB_FI_FAIL_AT=503 ./.libs/fi_sweep --one.Bug C — ASan leak (
__db_join,src/db/db_join.c:93). Allocates the join cursor, then leaks it when a later alloc in the join wiring fails. Repro:DB_FI_FAIL_AT=641 ./.libs/fi_sweep --one.Bug A is caught by both the forking sweep (CRASH) and ASan (SEGV); Bugs B/C are leaks only ASan sees (advisory). Full detail + fix shapes in
test/faultinject/README.md.CI
The full plain-debug sweep stays the gate; the ASan one-shot pass should sweep the full K = 1..M range (not stop at 260) so it reaches the new region past K = 480. That workflow update needs
workflowtoken scope (agent pushes lack it), so it is staged astest/faultinject/faultinject.yml.workflowfor a maintainer to sync into.github/workflows/faultinject.yml; the installed workflow file is left unchanged in this PR. Both jobs remain advisory (continue-on-error).Validation
Built + run in the nix dev shell (
--enable-debug --enable-faultinject, plain andCC=clang -fsanitize=address). No engine code changed.