GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — sqlite: reject statement-less SQL in SQLTagStore by TrevorBurnham · Pull Request #65157 · nodejs/node

Conversation

@TrevorBurnham

@TrevorBurnham TrevorBurnham commented Aug 9, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Contributor

sqlite3_prepare_v2() returns SQLITE_OK without producing a statement when its input holds no SQL, such as a comment or an empty string. Neither caller checked for this.

SQLTagStore cached a StatementSync wrapping the null sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only guards against a null statement under SQLITE_ENABLE_API_ARMOR, and segfaulted:

const db = new DatabaseSync(':memory:');
const store = db.createTagStore();
store.run`-- comment`;  // segfault

All four query methods (run, get, all, iterate) were affected.

db.prepare() returned a StatementSync whose statement_ was null. Every method on it threw statement has been finalized, which was misleading because nothing had been finalized. It was also still inserted into statements_, and because IsFinalized() is true for a null statement, its destructor skipped UntrackStatement() and left a dangling pointer that a later close() would finalize.

Both now throw ERR_INVALID_ARG_VALUE at preparation. SQL that merely contains comments is unaffected.

Fixes: #65149

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

meixg reacted with thumbs up emoji
All reactions
  • 👍 1 reaction
@nodejs-github-bot

nodejs-github-bot commented Aug 9, 2026

Copy link
Copy Markdown
Collaborator

Review requested:

  • @nodejs/sqlite
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@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 Aug 9, 2026
@Renegade334 Renegade334 mentioned this pull request Aug 9, 2026
sqlite: reject statement-less SQLTagStore queries #65152
Closed
Renegade334
Renegade334 reviewed Aug 9, 2026
View reviewed changes
Comment thread src/node_sqlite.cc Resolved

Uh oh!

There was an error while loading. Please reload this page.

TrevorBurnham added a commit to TrevorBurnham/node that referenced this pull request Aug 9, 2026
@TrevorBurnham
sqlite: reject statement-less SQL in prepare()
af2725f
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: nodejs#65157 (comment)

Signed-off-by: Trevor Burnham <[email protected]>
TrevorBurnham added a commit to TrevorBurnham/node that referenced this pull request Aug 9, 2026
@TrevorBurnham
sqlite: reject statement-less SQL in prepare()
3d2d495
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: nodejs#65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
@TrevorBurnham
TrevorBurnham force-pushed the sqlite/fix-tagstore-null-stmt branch from af2725f to 3d2d495 Compare August 9, 2026 15:55
Renegade334
Renegade334 approved these changes Aug 9, 2026
View reviewed changes

@Renegade334 Renegade334 left a comment

Copy link
Copy Markdown
Member

There was a problem hiding this comment.

Choose a reason for hiding this comment

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

👍👍

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Renegade334
Renegade334 reviewed Aug 9, 2026
View reviewed changes
Comment thread doc/api/sqlite.md Resolved

Uh oh!

There was an error while loading. Please reload this page.

TrevorBurnham added a commit to TrevorBurnham/node that referenced this pull request Aug 9, 2026
@TrevorBurnham
sqlite: reject statement-less SQL in prepare()
45be4bd
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: nodejs#65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
@TrevorBurnham
TrevorBurnham force-pushed the sqlite/fix-tagstore-null-stmt branch from 3d2d495 to 45be4bd Compare August 9, 2026 19:18
@TrevorBurnham
TrevorBurnham marked this pull request as ready for review August 9, 2026 23:47
trivikr
trivikr approved these changes Aug 10, 2026
View reviewed changes
@trivikr trivikr added author ready PRs with CI started, the required approvals, and no outstanding review comments. commit-queue PRs queued for automated landing through the Commit Queue. commit-queue-squash PRs the Commit Queue should land as one squashed commit. commit-queue-rebase PRs the Commit Queue should land as multiple self-contained commits. request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. and removed commit-queue-squash PRs the Commit Queue should land as one squashed commit. labels Aug 10, 2026
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Aug 10, 2026
@nodejs-github-bot

This comment was marked as resolved.

Sign in to view
@codecov

codecov Bot commented Aug 10, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 90.33%. Comparing base (b2b7405) to head (d7ad352).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main   #65157      +/-   ##
==========================================
- Coverage   90.33%   90.33%   -0.01%     
==========================================
  Files         760      760              
  Lines      248523   248529       +6     
  Branches    46906    46895      -11     
==========================================
- Hits       224511   224509       -2     
+ Misses      15451    15450       -1     
- Partials     8561     8570       +9     
Files with missing lines Coverage Δ
src/node_sqlite.cc 81.49% <100.00%> (+0.25%) ⬆️

... and 23 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.
All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

TrevorBurnham added 2 commits August 9, 2026 21:41
@TrevorBurnham
sqlite: reject statement-less SQL in SQLTagStore
4c2c3a4
sqlite3_prepare_v2() returns SQLITE_OK without producing a statement
when its input holds no SQL, such as a comment. PrepareStatement() only
checked the return code, so it cached a StatementSync wrapping a null
sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only
guards against a null statement under SQLITE_ENABLE_API_ARMOR, and
segfaulted.

Reject such input instead of caching it. The StatementSync methods
already avoid the crash because their IsFinalized() guard treats a null
statement as finalized.

Fixes: nodejs#65149

Signed-off-by: Trevor Burnham <[email protected]>
@TrevorBurnham
sqlite: reject statement-less SQL in prepare()
d7ad352
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: nodejs#65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
@TrevorBurnham
TrevorBurnham force-pushed the sqlite/fix-tagstore-null-stmt branch from 45be4bd to d7ad352 Compare August 10, 2026 01:49
@trivikr trivikr added the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Aug 10, 2026
trivikr
trivikr approved these changes Aug 10, 2026
View reviewed changes
@github-actions github-actions Bot removed the request-ci Add this label to start a Jenkins CI on a PR. Only starts once the PR has an approving review. label Aug 10, 2026
@nodejs-github-bot

nodejs-github-bot commented Aug 10, 2026

Copy link
Copy Markdown
Collaborator

CI: https://ci.nodejs.org/job/node-test-pull-request/75723/

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@nodejs-github-bot

nodejs-github-bot commented Aug 11, 2026

Copy link
Copy Markdown
Collaborator

Landed in a576f1c...cb9bb66

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

nodejs-github-bot pushed a commit that referenced this pull request Aug 11, 2026
@TrevorBurnham @nodejs-github-bot
sqlite: reject statement-less SQL in SQLTagStore
71b3676
sqlite3_prepare_v2() returns SQLITE_OK without producing a statement
when its input holds no SQL, such as a comment. PrepareStatement() only
checked the return code, so it cached a StatementSync wrapping a null
sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only
guards against a null statement under SQLITE_ENABLE_API_ARMOR, and
segfaulted.

Reject such input instead of caching it. The StatementSync methods
already avoid the crash because their IsFinalized() guard treats a null
statement as finalized.

Fixes: #65149

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
@nodejs-github-bot nodejs-github-bot closed this Aug 11, 2026
nodejs-github-bot pushed a commit that referenced this pull request Aug 11, 2026
@TrevorBurnham @nodejs-github-bot
sqlite: reject statement-less SQL in prepare()
cb9bb66
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: #65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
@nodejs-github-bot nodejs-github-bot removed the commit-queue PRs queued for automated landing through the Commit Queue. label Aug 11, 2026
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in SQLTagStore
48918a3
sqlite3_prepare_v2() returns SQLITE_OK without producing a statement
when its input holds no SQL, such as a comment. PrepareStatement() only
checked the return code, so it cached a StatementSync wrapping a null
sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only
guards against a null statement under SQLITE_ENABLE_API_ARMOR, and
segfaulted.

Reject such input instead of caching it. The StatementSync methods
already avoid the crash because their IsFinalized() guard treats a null
statement as finalized.

Fixes: #65149

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
aduh95 pushed a commit that referenced this pull request Aug 13, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in prepare()
2ef0493
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: #65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in SQLTagStore
83169e5
sqlite3_prepare_v2() returns SQLITE_OK without producing a statement
when its input holds no SQL, such as a comment. PrepareStatement() only
checked the return code, so it cached a StatementSync wrapping a null
sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only
guards against a null statement under SQLITE_ENABLE_API_ARMOR, and
segfaulted.

Reject such input instead of caching it. The StatementSync methods
already avoid the crash because their IsFinalized() guard treats a null
statement as finalized.

Fixes: #65149

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
aduh95 pushed a commit that referenced this pull request Aug 25, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in prepare()
5e387ce
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: #65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
@github-actions github-actions Bot mentioned this pull request Aug 25, 2026
2026-08-26, Version 26.8.0 (Current) #65551
Merged
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in SQLTagStore
043dfe4
sqlite3_prepare_v2() returns SQLITE_OK without producing a statement
when its input holds no SQL, such as a comment. PrepareStatement() only
checked the return code, so it cached a StatementSync wrapping a null
sqlite3_stmt. Executing it reached sqlite3_clear_bindings(), which only
guards against a null statement under SQLITE_ENABLE_API_ARMOR, and
segfaulted.

Reject such input instead of caching it. The StatementSync methods
already avoid the crash because their IsFinalized() guard treats a null
statement as finalized.

Fixes: #65149

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
aduh95 pushed a commit that referenced this pull request Aug 27, 2026
@TrevorBurnham @aduh95
sqlite: reject statement-less SQL in prepare()
6ae81be
Apply the same check to DatabaseSync::Prepare() so that statement-less
SQL is rejected at preparation instead of on first use. This matches
SQLite's own oo1 JavaScript API, which throws when the SQL contains no
statements rather than exposing the C API's null statement pointer.

Previously db.prepare('-- comment') returned a StatementSync whose
statement_ was null. Every method on it threw "statement has been
finalized", which was misleading because nothing had been finalized, and
the object was still inserted into statements_. Since IsFinalized() is
true for a null statement, its destructor skipped UntrackStatement() and
left a dangling pointer in the set that a later close() would finalize.

Refs: #65157 (comment)
Refs: https://sqlite.org/wasm/doc/trunk/api-oo1.md

Signed-off-by: Trevor Burnham <[email protected]>
PR-URL: #65157
Fixes: #65149
Reviewed-By: René <[email protected]>
Reviewed-By: Trivikram Kamat <[email protected]>
@github-actions github-actions Bot mentioned this pull request Sep 7, 2026
2026-09-08, Version 24.21.0 'Krypton' (LTS) #65873
Merged
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Renegade334 Renegade334 Renegade334 approved these changes
@trivikr trivikr trivikr approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

author ready PRs with CI started, the required approvals, and no outstanding review comments. c++ Issues and PRs that require attention from people who are familiar with C++. commit-queue-rebase PRs the Commit Queue should land as multiple self-contained commits. needs-ci PRs that need a full CI run. sqlite Issues and PRs related to the SQLite subsystem.

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

sqlite: segfault when a SQLTagStore query contains only a comment

Uh oh!

There was an error while loading. Please reload this page.

4 participants

@TrevorBurnham @nodejs-github-bot @Renegade334 @trivikr
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.