Skip to content

Commit a151cb6

Browse files
committed
fix(Session): prevent use-after-free when database is GC'd before session
The Session class was using a raw DatabaseSync* pointer without holding a reference to keep the database object alive. When JavaScript lost its reference to the DatabaseSync and GC ran, the database destructor would be called while Sessions still referenced it, causing SIGSEGV on Alpine Linux. Fix: Add Napi::ObjectReference database_ref_ to Session class, matching the pattern used by StatementSync to prevent the same issue. Fixes: SIGSEGV in session-lifecycle.test.ts on Alpine Linux (ARM64/x64)
1 parent b5835fa commit a151cb6

File tree

2 files changed

+14
-0
lines changed

2 files changed

+14
-0
lines changed

src/sqlite_impl.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2974,6 +2974,11 @@ void Session::SetSession(DatabaseSync *database, sqlite3_session *session) {
29742974
session_ = session;
29752975
if (database_) {
29762976
database_->AddSession(this);
2977+
// Create a strong reference to the database object to prevent it from being
2978+
// garbage collected while this session exists. This fixes use-after-free
2979+
// when the database is GC'd before its sessions.
2980+
// See: https://github.com/nodejs/node/pull/56840 (similar fix for statements)
2981+
database_ref_ = Napi::Persistent(database->Value());
29772982
}
29782983
}
29792984

@@ -2996,6 +3001,11 @@ void Session::Delete() {
29963001

29973002
// Now it's safe to delete the SQLite session
29983003
sqlite3session_delete(session_to_delete);
3004+
3005+
// Release the strong reference to the database object
3006+
if (!database_ref_.IsEmpty()) {
3007+
database_ref_.Reset();
3008+
}
29993009
}
30003010

30013011
template <int (*sqliteChangesetFunc)(sqlite3_session *, int *, void **)>

src/sqlite_impl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,10 @@ class Session : public Napi::ObjectWrap<Session> {
360360

361361
sqlite3_session *session_ = nullptr;
362362
DatabaseSync *database_ = nullptr; // Direct pointer to database
363+
// Strong reference to database object to prevent GC while session exists.
364+
// This fixes use-after-free when database is GC'd before its sessions.
365+
// See: https://github.com/nodejs/node/pull/56840 (similar fix for statements)
366+
Napi::ObjectReference database_ref_;
363367

364368
friend class DatabaseSync;
365369
};

0 commit comments

Comments
 (0)