Skip to content

Commit d6cf091

Browse files
jasnelltargos
authored andcommitted
src: improve error handling in node_sqlite
PR-URL: #56891 Reviewed-By: Michaël Zasso <targos@protonmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
1 parent 8410c95 commit d6cf091

File tree

1 file changed

+104
-54
lines changed

1 file changed

+104
-54
lines changed

src/node_sqlite.cc

Lines changed: 104 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -126,13 +126,15 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
126126
const char* errstr = sqlite3_errstr(errcode);
127127

128128
Environment* env = Environment::GetCurrent(isolate);
129-
auto error = CreateSQLiteError(isolate, errstr).ToLocalChecked();
130-
error
131-
->Set(isolate->GetCurrentContext(),
132-
env->errcode_string(),
133-
Integer::New(isolate, errcode))
134-
.ToChecked();
135-
isolate->ThrowException(error);
129+
Local<Object> error;
130+
if (CreateSQLiteError(isolate, errstr).ToLocal(&error) &&
131+
error
132+
->Set(isolate->GetCurrentContext(),
133+
env->errcode_string(),
134+
Integer::New(isolate, errcode))
135+
.IsJust()) {
136+
isolate->ThrowException(error);
137+
}
136138
}
137139

138140
UserDefinedFunction::UserDefinedFunction(Environment* env,
@@ -734,12 +736,14 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
734736
}
735737
}
736738

737-
Local<String> db_key =
738-
String::NewFromUtf8(env->isolate(), "db", NewStringType::kNormal)
739-
.ToLocalChecked();
739+
Local<String> db_key = FIXED_ONE_BYTE_STRING(env->isolate(), "db");
740+
740741
if (options->HasOwnProperty(env->context(), db_key).FromJust()) {
741-
Local<Value> db_value =
742-
options->Get(env->context(), db_key).ToLocalChecked();
742+
Local<Value> db_value;
743+
if (!options->Get(env->context(), db_key).ToLocal(&db_value)) {
744+
// An error will have been scheduled.
745+
return;
746+
}
743747
if (db_value->IsString()) {
744748
String::Utf8Value str(env->isolate(), db_value);
745749
db_name = std::string(*str);
@@ -808,8 +812,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
808812
}
809813

810814
Local<Object> options = args[1].As<Object>();
811-
Local<Value> conflictValue =
812-
options->Get(env->context(), env->onconflict_string()).ToLocalChecked();
815+
Local<Value> conflictValue;
816+
if (!options->Get(env->context(), env->onconflict_string())
817+
.ToLocal(&conflictValue)) {
818+
// An error will have been scheduled.
819+
return;
820+
}
813821

814822
if (!conflictValue->IsUndefined()) {
815823
if (!conflictValue->IsFunction()) {
@@ -837,8 +845,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
837845

838846
if (options->HasOwnProperty(env->context(), env->filter_string())
839847
.FromJust()) {
840-
Local<Value> filterValue =
841-
options->Get(env->context(), env->filter_string()).ToLocalChecked();
848+
Local<Value> filterValue;
849+
if (!options->Get(env->context(), env->filter_string())
850+
.ToLocal(&filterValue)) {
851+
// An error will have been scheduled.
852+
return;
853+
}
842854

843855
if (!filterValue->IsFunction()) {
844856
THROW_ERR_INVALID_ARG_TYPE(
@@ -850,6 +862,10 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
850862
Local<Function> filterFunc = filterValue.As<Function>();
851863

852864
filterCallback = [env, filterFunc](std::string item) -> bool {
865+
// TODO(@jasnell): The use of ToLocalChecked here means that if
866+
// the filter function throws an error the process will crash.
867+
// The filterCallback should be updated to avoid the check and
868+
// propagate the error correctly.
853869
Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),
854870
item.c_str(),
855871
NewStringType::kNormal)
@@ -1214,11 +1230,18 @@ void StatementSync::IterateReturnCallback(
12141230

12151231
auto self = args.This();
12161232
// iterator has fetch all result or break, prevent next func to return result
1217-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1218-
.ToChecked();
1233+
if (self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1234+
.IsNothing()) {
1235+
// An error will have been scheduled.
1236+
return;
1237+
}
12191238

1220-
auto external_stmt = Local<External>::Cast(
1221-
self->Get(context, env->statement_string()).ToLocalChecked());
1239+
Local<Value> val;
1240+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1241+
// An error will have been scheduled.
1242+
return;
1243+
}
1244+
auto external_stmt = Local<External>::Cast(val);
12221245
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
12231246
if (!stmt->IsFinalized()) {
12241247
sqlite3_reset(stmt->statement_);
@@ -1242,28 +1265,38 @@ void StatementSync::IterateNextCallback(
12421265

12431266
auto self = args.This();
12441267

1268+
Local<Value> val;
1269+
if (!self->Get(context, env->isfinished_string()).ToLocal(&val)) {
1270+
// An error will have been scheduled.
1271+
return;
1272+
}
1273+
12451274
// skip iteration if is_finished
1246-
auto is_finished = Local<Boolean>::Cast(
1247-
self->Get(context, env->isfinished_string()).ToLocalChecked());
1275+
auto is_finished = Local<Boolean>::Cast(val);
12481276
if (is_finished->Value()) {
1249-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1250-
LocalVector<Value> values(isolate,
1251-
{Boolean::New(isolate, true), Null(isolate)});
1252-
1253-
DCHECK_EQ(keys.size(), values.size());
1277+
Local<Name> keys[] = {env->done_string(), env->value_string()};
1278+
Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
1279+
static_assert(arraysize(keys) == arraysize(values));
12541280
Local<Object> result = Object::New(
1255-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1281+
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
12561282
args.GetReturnValue().Set(result);
12571283
return;
12581284
}
12591285

1260-
auto external_stmt = Local<External>::Cast(
1261-
self->Get(context, env->statement_string()).ToLocalChecked());
1286+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1287+
// An error will have been scheduled.
1288+
return;
1289+
}
1290+
1291+
auto external_stmt = Local<External>::Cast(val);
12621292
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
1263-
auto num_cols =
1264-
Local<Integer>::Cast(
1265-
self->Get(context, env->num_cols_string()).ToLocalChecked())
1266-
->Value();
1293+
1294+
if (!self->Get(context, env->num_cols_string()).ToLocal(&val)) {
1295+
// An error will have been scheduled.
1296+
return;
1297+
}
1298+
1299+
auto num_cols = Local<Integer>::Cast(val)->Value();
12671300

12681301
THROW_AND_RETURN_ON_BAD_STATE(
12691302
env, stmt->IsFinalized(), "statement has been finalized");
@@ -1275,8 +1308,12 @@ void StatementSync::IterateNextCallback(
12751308

12761309
// cleanup when no more rows to fetch
12771310
sqlite3_reset(stmt->statement_);
1278-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1279-
.ToChecked();
1311+
if (self->Set(
1312+
context, env->isfinished_string(), Boolean::New(isolate, true))
1313+
.IsNothing()) {
1314+
// An error would have been scheduled
1315+
return;
1316+
}
12801317

12811318
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
12821319
LocalVector<Value> values(isolate,
@@ -1329,15 +1366,19 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13291366
return;
13301367
}
13311368

1332-
Local<Function> next_func =
1333-
Function::New(context, StatementSync::IterateNextCallback)
1334-
.ToLocalChecked();
1335-
Local<Function> return_func =
1336-
Function::New(context, StatementSync::IterateReturnCallback)
1337-
.ToLocalChecked();
1369+
Local<Function> next_func;
1370+
Local<Function> return_func;
1371+
if (!Function::New(context, StatementSync::IterateNextCallback)
1372+
.ToLocal(&next_func) ||
1373+
!Function::New(context, StatementSync::IterateReturnCallback)
1374+
.ToLocal(&return_func)) {
1375+
// An error will have been scheduled.
1376+
return;
1377+
}
13381378

1339-
LocalVector<Name> keys(isolate, {env->next_string(), env->return_string()});
1340-
LocalVector<Value> values(isolate, {next_func, return_func});
1379+
Local<Name> keys[] = {env->next_string(), env->return_string()};
1380+
Local<Value> values[] = {next_func, return_func};
1381+
static_assert(arraysize(keys) == arraysize(values));
13411382

13421383
Local<Object> global = context->Global();
13431384
Local<Value> js_iterator;
@@ -1349,32 +1390,41 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13491390
.ToLocal(&js_iterator_prototype))
13501391
return;
13511392

1352-
DCHECK_EQ(keys.size(), values.size());
13531393
Local<Object> iterable_iterator = Object::New(
1354-
isolate, js_iterator_prototype, keys.data(), values.data(), keys.size());
1394+
isolate, js_iterator_prototype, &keys[0], &values[0], arraysize(keys));
13551395

13561396
auto num_cols_pd = v8::PropertyDescriptor(
13571397
v8::Integer::New(isolate, sqlite3_column_count(stmt->statement_)), false);
13581398
num_cols_pd.set_enumerable(false);
13591399
num_cols_pd.set_configurable(false);
1360-
iterable_iterator
1361-
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1362-
.ToChecked();
1400+
if (iterable_iterator
1401+
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1402+
.IsNothing()) {
1403+
// An error will have been scheduled.
1404+
return;
1405+
}
13631406

13641407
auto stmt_pd =
13651408
v8::PropertyDescriptor(v8::External::New(isolate, stmt), false);
13661409
stmt_pd.set_enumerable(false);
13671410
stmt_pd.set_configurable(false);
1368-
iterable_iterator->DefineProperty(context, env->statement_string(), stmt_pd)
1369-
.ToChecked();
1411+
if (iterable_iterator
1412+
->DefineProperty(context, env->statement_string(), stmt_pd)
1413+
.IsNothing()) {
1414+
// An error will have been scheduled.
1415+
return;
1416+
}
13701417

13711418
auto is_finished_pd =
13721419
v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);
13731420
stmt_pd.set_enumerable(false);
13741421
stmt_pd.set_configurable(false);
1375-
iterable_iterator
1376-
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1377-
.ToChecked();
1422+
if (iterable_iterator
1423+
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1424+
.IsNothing()) {
1425+
// An error will have been scheduled.
1426+
return;
1427+
}
13781428

13791429
args.GetReturnValue().Set(iterable_iterator);
13801430
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy