Skip to content

sqlite: reject deserialize() while in a callback - #64796

Open
trivikr wants to merge 3 commits into
nodejs:mainfrom
trivikr:sqlite-reject-reentrant-close
Open

sqlite: reject deserialize() while in a callback#64796
trivikr wants to merge 3 commits into
nodejs:mainfrom
trivikr:sqlite-reject-reentrant-close

Conversation

@trivikr

@trivikr trivikr commented Jul 28, 2026

Copy link
Copy Markdown
Member

Fixes: #64795

deserialize() could be called from a user-defined function invoked during statement execution, tearing down the database connection while sqlite3_step() was still using it. Reuse the existing callback depth check to throw ERR_INVALID_STATE instead, matching the guard already in place for close().


Assisted-by: codex:gpt-5.6-sol

@nodejs-github-bot

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite

@nodejs-github-bot nodejs-github-bot added c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem. labels Jul 28, 2026
@codecov

codecov Bot commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.31%. Comparing base (6c862f4) to head (0081aa8).
⚠️ Report is 2 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #64796      +/-   ##
==========================================
+ Coverage   90.29%   90.31%   +0.02%     
==========================================
  Files         759      759              
  Lines      248295   248296       +1     
  Branches    46861    46857       -4     
==========================================
+ Hits       224205   224258      +53     
+ Misses      15517    15465      -52     
  Partials     8573     8573              
Files with missing lines Coverage Δ
src/node_sqlite.cc 80.84% <100.00%> (+<0.01%) ⬆️

... and 26 files with indirect coverage changes

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@trivikr trivikr added the request-ci Add this label to start a Jenkins CI on a PR. label Jul 28, 2026
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch from c11abfd to 4af37c6 Compare July 31, 2026 04:28
@trivikr
trivikr requested a review from geeksilva97 August 2, 2026 02:56
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch from 4af37c6 to c64b289 Compare August 3, 2026 19:58
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch 3 times, most recently from 46139cd to e6c5c8c Compare August 5, 2026 02:22

@TrevorBurnham TrevorBurnham left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The guard itself looks right to me: IsInCallback() is the correct predicate, since the crash needs a live sqlite3_step() frame, which is only reachable from a callback, and every step-reentrant entry point (xFunc, xStepBase/xValueBase, the authorizer, sqlite3changeset_apply) already takes CallbackDepthGuard. Placing it before FinalizeStatements() also means a rejected call leaves no partial state. Three non-blocking notes below, plus one on the docs.

doc/api/sqlite.md: the new throwing condition isn't documented. The database.deserialize() section only mentions that existing statements are finalized first; it'd help to state that the method throws ERR_INVALID_STATE when called from a user-defined function, aggregate, authorizer, or changeset filter/conflict callback. The same is missing for database.close() from #64743 — might be worth adding both here.

Comment thread src/node_sqlite.cc
Comment thread test/parallel/test-sqlite-serialize.js Outdated
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch from e6c5c8c to 19c3939 Compare August 6, 2026 18:10
@trivikr trivikr changed the title sqlite: prevent reentrant statement finalization sqlite: reject deserialize() while in a callback Aug 6, 2026
trivikr added 2 commits August 6, 2026 19:56
deserialize() could be called from a user-defined function invoked
during statement execution, tearing down the database connection while
sqlite3_step() was still using it. Reuse the existing callback depth
check to throw ERR_INVALID_STATE instead, matching the guard already
in place for close().

Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com>
Assisted-by: codex:gpt-5.6-sol
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch from 0f44d09 to ae8a08a Compare August 7, 2026 02:56
@trivikr
trivikr force-pushed the sqlite-reject-reentrant-close branch from ae8a08a to 0081aa8 Compare August 7, 2026 03:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

c++ Issues and PRs that require attention from people who are familiar with C++. needs-ci PRs that need a full CI run. request-ci Add this label to start a Jenkins CI on a PR. sqlite Issues and PRs related to the SQLite subsystem.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

sqlite: prevent reentrant statement finalization from callbacks

3 participants