Skip to content

Commit ce8ae58

Browse files
committed
fix(statement): add strong reference to database object to prevent use-after-free
1 parent e88ed00 commit ce8ae58

File tree

2 files changed

+14
-1
lines changed

2 files changed

+14
-1
lines changed

src/sqlite_impl.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1439,6 +1439,11 @@ void StatementSync::InitStatement(DatabaseSync *database,
14391439
}
14401440

14411441
database_ = database;
1442+
// Create a strong reference to the database object to prevent it from being
1443+
// garbage collected while this statement exists. This fixes use-after-free
1444+
// when the database is GC'd before its statements.
1445+
// See: https://github.com/nodejs/node/pull/56840
1446+
database_ref_ = Napi::Persistent(database->Value());
14421447
source_sql_ = sql;
14431448

14441449
// Apply database-level defaults
@@ -1470,6 +1475,10 @@ StatementSync::~StatementSync() {
14701475
if (statement_ && !finalized_) {
14711476
sqlite3_finalize(statement_);
14721477
}
1478+
// Release the strong reference to the database object
1479+
if (!database_ref_.IsEmpty()) {
1480+
database_ref_.Reset();
1481+
}
14731482
}
14741483

14751484
Napi::Value StatementSync::Run(const Napi::CallbackInfo &info) {

src/sqlite_impl.h

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -267,7 +267,11 @@ class StatementSync : public Napi::ObjectWrap<StatementSync> {
267267
Napi::Value CreateResult();
268268
void Reset();
269269

270-
DatabaseSync *database_;
270+
DatabaseSync *database_ = nullptr;
271+
// Strong reference to database object to prevent GC while statement exists.
272+
// This fixes use-after-free when database is GC'd before its statements.
273+
// See: https://github.com/nodejs/node/pull/56840
274+
Napi::ObjectReference database_ref_;
271275
sqlite3_stmt *statement_ = nullptr;
272276
std::string source_sql_;
273277
bool finalized_ = false;

0 commit comments

Comments
 (0)