-
Notifications
You must be signed in to change notification settings - Fork 30.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
sqlite: fix use-after-free in StatementSync due to premature GC #56840
Conversation
9ca3cc0
to
4373e55
Compare
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.
LGTM, thanks!
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #56840 +/- ##
==========================================
+ Coverage 89.18% 89.20% +0.01%
==========================================
Files 665 665
Lines 192543 192542 -1
Branches 37045 37051 +6
==========================================
+ Hits 171726 171749 +23
- Misses 13636 13639 +3
+ Partials 7181 7154 -27
|
Hm, it looks like there may be related failures on Windows while trying to clean up:
This happened a number of times on Windows. I'll restart the CI to see if that was a one off issue, but I have a feeling it's legit. |
The latest run had the same file files blocking cleanup. They appear to correspond to these five tests. I'm not sure off the top of my head why those ones would be blocking. I do see that the two |
4373e55
to
7185964
Compare
I updated the two |
@littledivy can you apply these changes. These should resolve the test failures now due to a conflicting change that landed. diff --git a/src/node_sqlite.cc b/src/node_sqlite.cc
index 39e1be871d..1639c196ce 100644
--- a/src/node_sqlite.cc
+++ b/src/node_sqlite.cc
@@ -977,7 +977,7 @@ inline bool StatementSync::IsFinalized() {
bool StatementSync::BindParams(const FunctionCallbackInfo<Value>& args) {
int r = sqlite3_clear_bindings(statement_);
- CHECK_ERROR_OR_THROW(env()->isolate(), db_, r, SQLITE_OK, false);
+ CHECK_ERROR_OR_THROW(env()->isolate(), db_.get(), r, SQLITE_OK, false);
int anon_idx = 1;
int anon_start = 0;
@@ -1107,7 +1107,7 @@ bool StatementSync::BindValue(const Local<Value>& value, const int index) {
return false;
}
- CHECK_ERROR_OR_THROW(env()->isolate(), db_, r, SQLITE_OK, false);
+ CHECK_ERROR_OR_THROW(env()->isolate(), db_.get(), r, SQLITE_OK, false);
return true;
}
@@ -1173,7 +1173,7 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
env, stmt->IsFinalized(), "statement has been finalized");
Isolate* isolate = env->isolate();
int r = sqlite3_reset(stmt->statement_);
- CHECK_ERROR_OR_THROW(isolate, stmt->db_, r, SQLITE_OK, void());
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
if (!stmt->BindParams(args)) {
return;
@@ -1202,7 +1202,7 @@ void StatementSync::All(const FunctionCallbackInfo<Value>& args) {
rows.emplace_back(row);
}
- CHECK_ERROR_OR_THROW(isolate, stmt->db_, r, SQLITE_DONE, void());
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_DONE, void());
args.GetReturnValue().Set(Array::New(isolate, rows.data(), rows.size()));
}
@@ -1270,7 +1270,8 @@ void StatementSync::IterateNextCallback(
int r = sqlite3_step(stmt->statement_);
if (r != SQLITE_ROW) {
- CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_, r, SQLITE_DONE, void());
+ CHECK_ERROR_OR_THROW(
+ env->isolate(), stmt->db_.get(), r, SQLITE_DONE, void());
// cleanup when no more rows to fetch
sqlite3_reset(stmt->statement_);
@@ -1322,7 +1323,7 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
auto isolate = env->isolate();
auto context = env->context();
int r = sqlite3_reset(stmt->statement_);
- CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_, r, SQLITE_OK, void());
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
if (!stmt->BindParams(args)) {
return;
@@ -1386,7 +1387,7 @@ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
env, stmt->IsFinalized(), "statement has been finalized");
Isolate* isolate = env->isolate();
int r = sqlite3_reset(stmt->statement_);
- CHECK_ERROR_OR_THROW(isolate, stmt->db_, r, SQLITE_OK, void());
+ CHECK_ERROR_OR_THROW(isolate, stmt->db_.get(), r, SQLITE_OK, void());
if (!stmt->BindParams(args)) {
return;
@@ -1396,7 +1397,7 @@ void StatementSync::Get(const FunctionCallbackInfo<Value>& args) {
r = sqlite3_step(stmt->statement_);
if (r == SQLITE_DONE) return;
if (r != SQLITE_ROW) {
- THROW_ERR_SQLITE_ERROR(isolate, stmt->db_);
+ THROW_ERR_SQLITE_ERROR(isolate, stmt->db_.get());
return;
}
@@ -1432,7 +1433,7 @@ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
THROW_AND_RETURN_ON_BAD_STATE(
env, stmt->IsFinalized(), "statement has been finalized");
int r = sqlite3_reset(stmt->statement_);
- CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_, r, SQLITE_OK, void());
+ CHECK_ERROR_OR_THROW(env->isolate(), stmt->db_.get(), r, SQLITE_OK, void());
if (!stmt->BindParams(args)) {
return;
@@ -1441,7 +1442,7 @@ void StatementSync::Run(const FunctionCallbackInfo<Value>& args) {
auto reset = OnScopeLeave([&]() { sqlite3_reset(stmt->statement_); });
r = sqlite3_step(stmt->statement_);
if (r != SQLITE_ROW && r != SQLITE_DONE) {
- THROW_ERR_SQLITE_ERROR(env->isolate(), stmt->db_);
+ THROW_ERR_SQLITE_ERROR(env->isolate(), stmt->db_.get());
return;
}
@@ -1674,7 +1675,7 @@ void Session::Changeset(const FunctionCallbackInfo<Value>& args) {
void* pChangeset;
int r = sqliteChangesetFunc(session->session_, &nChangeset, &pChangeset);
CHECK_ERROR_OR_THROW(
- env->isolate(), session->database_, r, SQLITE_OK, void());
+ env->isolate(), session->database_.get(), r, SQLITE_OK, void());
auto freeChangeset = OnScopeLeave([&] { sqlite3_free(pChangeset); });
|
597b2c2
to
e91a418
Compare
PR-URL: #56469 Reviewed-By: Jacob Smith <jacob@frende.me> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Bryan English <bryan@bryanenglish.com>
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.
LGTM. Thanks again.
Landed in cebf4c8 |
PR-URL: #56840 Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This patch updates
StatementSync
to store a strong reference to the database base object.DatabaseSync
may be garbage collected and freed whileStatementSync
is using it (due toMakeWeak()
). The following code crashes with a segmentation fault: