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 <[email protected]> Reviewed-By: Colin Ihrig <[email protected]>
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

+104-54
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)