Skip to content

Commit 9d75ad4

Browse files
committed
src: improve error handling in node_sqlite
1 parent cadc4ed commit 9d75ad4

File tree

1 file changed

+104
-53
lines changed

1 file changed

+104
-53
lines changed

src/node_sqlite.cc

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

121121
Environment* env = Environment::GetCurrent(isolate);
122-
auto error = CreateSQLiteError(isolate, errstr).ToLocalChecked();
123-
error
124-
->Set(isolate->GetCurrentContext(),
125-
env->errcode_string(),
126-
Integer::New(isolate, errcode))
127-
.ToChecked();
128-
isolate->ThrowException(error);
122+
Local<Object> error;
123+
if (CreateSQLiteError(isolate, errstr).ToLocal(&error) &&
124+
error
125+
->Set(isolate->GetCurrentContext(),
126+
env->errcode_string(),
127+
Integer::New(isolate, errcode))
128+
.IsJust()) {
129+
isolate->ThrowException(error);
130+
}
129131
}
130132

131133
class UserDefinedFunction {
@@ -709,12 +711,14 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
709711
}
710712
}
711713

712-
Local<String> db_key =
713-
String::NewFromUtf8(env->isolate(), "db", NewStringType::kNormal)
714-
.ToLocalChecked();
714+
Local<String> db_key = FIXED_ONE_BYTE_STRING(env->isolate(), "db");
715+
715716
if (options->HasOwnProperty(env->context(), db_key).FromJust()) {
716-
Local<Value> db_value =
717-
options->Get(env->context(), db_key).ToLocalChecked();
717+
Local<Value> db_value;
718+
if (!options->Get(env->context(), db_key).ToLocal(&db_value)) {
719+
// An error will have been scheduled.
720+
return;
721+
}
718722
if (db_value->IsString()) {
719723
String::Utf8Value str(env->isolate(), db_value);
720724
db_name = std::string(*str);
@@ -783,8 +787,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
783787
}
784788

785789
Local<Object> options = args[1].As<Object>();
786-
Local<Value> conflictValue =
787-
options->Get(env->context(), env->onconflict_string()).ToLocalChecked();
790+
Local<Value> conflictValue;
791+
if (!options->Get(env->context(), env->onconflict_string())
792+
.ToLocal(&conflictValue)) {
793+
// An error will have been scheduled.
794+
return;
795+
}
788796

789797
if (!conflictValue->IsUndefined()) {
790798
if (!conflictValue->IsFunction()) {
@@ -812,8 +820,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
812820

813821
if (options->HasOwnProperty(env->context(), env->filter_string())
814822
.FromJust()) {
815-
Local<Value> filterValue =
816-
options->Get(env->context(), env->filter_string()).ToLocalChecked();
823+
Local<Value> filterValue;
824+
if (!options->Get(env->context(), env->filter_string())
825+
.ToLocal(&filterValue)) {
826+
// An error will have been scheduled.
827+
return;
828+
}
817829

818830
if (!filterValue->IsFunction()) {
819831
THROW_ERR_INVALID_ARG_TYPE(
@@ -825,6 +837,10 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
825837
Local<Function> filterFunc = filterValue.As<Function>();
826838

827839
filterCallback = [env, filterFunc](std::string item) -> bool {
840+
// TODO(@jasnell): The use of ToLocalChecked here means that if
841+
// the filter function throws an error the process will crash.
842+
// The filterCallback should be updated to avoid the check and
843+
// propagate the error correctly.
828844
Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),
829845
item.c_str(),
830846
NewStringType::kNormal)
@@ -1194,11 +1210,18 @@ void StatementSync::IterateReturnCallback(
11941210

11951211
auto self = args.This();
11961212
// iterator has fetch all result or break, prevent next func to return result
1197-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1198-
.ToChecked();
1213+
if (self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1214+
.IsNothing()) {
1215+
// An error will have been scheduled.
1216+
return;
1217+
}
11991218

1200-
auto external_stmt = Local<External>::Cast(
1201-
self->Get(context, env->statement_string()).ToLocalChecked());
1219+
Local<Value> val;
1220+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1221+
// An error will have been scheduled.
1222+
return;
1223+
}
1224+
auto external_stmt = Local<External>::Cast(val);
12021225
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
12031226
if (!stmt->IsFinalized()) {
12041227
sqlite3_reset(stmt->statement_);
@@ -1222,28 +1245,38 @@ void StatementSync::IterateNextCallback(
12221245

12231246
auto self = args.This();
12241247

1248+
Local<Value> val;
1249+
if (!self->Get(context, env->isfinished_string()).ToLocal(&val)) {
1250+
// An error will have been scheduled.
1251+
return;
1252+
}
1253+
12251254
// skip iteration if is_finished
1226-
auto is_finished = Local<Boolean>::Cast(
1227-
self->Get(context, env->isfinished_string()).ToLocalChecked());
1255+
auto is_finished = Local<Boolean>::Cast(val);
12281256
if (is_finished->Value()) {
1229-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1230-
LocalVector<Value> values(isolate,
1231-
{Boolean::New(isolate, true), Null(isolate)});
1232-
1233-
DCHECK_EQ(keys.size(), values.size());
1257+
Local<Name> keys[] = {env->done_string(), env->value_string()};
1258+
Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
1259+
static_assert(arraysize(keys) == arraysize(values));
12341260
Local<Object> result = Object::New(
1235-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1261+
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
12361262
args.GetReturnValue().Set(result);
12371263
return;
12381264
}
12391265

1240-
auto external_stmt = Local<External>::Cast(
1241-
self->Get(context, env->statement_string()).ToLocalChecked());
1266+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1267+
// An error will have been scheduled.
1268+
return;
1269+
}
1270+
1271+
auto external_stmt = Local<External>::Cast(val);
12421272
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
1243-
auto num_cols =
1244-
Local<Integer>::Cast(
1245-
self->Get(context, env->num_cols_string()).ToLocalChecked())
1246-
->Value();
1273+
1274+
if (!self->Get(context, env->num_cols_string()).ToLocal(&val)) {
1275+
// An error will have been scheduled.
1276+
return;
1277+
}
1278+
1279+
auto num_cols = Local<Integer>::Cast(val)->Value();
12471280

12481281
THROW_AND_RETURN_ON_BAD_STATE(
12491282
env, stmt->IsFinalized(), "statement has been finalized");
@@ -1255,8 +1288,12 @@ void StatementSync::IterateNextCallback(
12551288

12561289
// cleanup when no more rows to fetch
12571290
sqlite3_reset(stmt->statement_);
1258-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1259-
.ToChecked();
1291+
if (self->Set(
1292+
context, env->isfinished_string(), Boolean::New(isolate, true))
1293+
.IsNothing()) {
1294+
// An error would have been scheduled
1295+
return;
1296+
}
12601297

12611298
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
12621299
LocalVector<Value> values(isolate,
@@ -1310,15 +1347,19 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13101347
return;
13111348
}
13121349

1313-
Local<Function> next_func =
1314-
Function::New(context, StatementSync::IterateNextCallback)
1315-
.ToLocalChecked();
1316-
Local<Function> return_func =
1317-
Function::New(context, StatementSync::IterateReturnCallback)
1318-
.ToLocalChecked();
1350+
Local<Function> next_func;
1351+
Local<Function> return_func;
1352+
if (!Function::New(context, StatementSync::IterateNextCallback)
1353+
.ToLocal(&next_func) ||
1354+
!Function::New(context, StatementSync::IterateReturnCallback)
1355+
.ToLocal(&return_func)) {
1356+
// An error will have been scheduled.
1357+
return;
1358+
}
13191359

1320-
LocalVector<Name> keys(isolate, {env->next_string(), env->return_string()});
1321-
LocalVector<Value> values(isolate, {next_func, return_func});
1360+
Local<Name> keys[] = {env->next_string(), env->return_string()};
1361+
Local<Value> values[] = {next_func, return_func};
1362+
static_assert(arraysize(keys) == arraysize(values));
13221363

13231364
Local<Object> global = context->Global();
13241365
Local<Value> js_iterator;
@@ -1332,30 +1373,40 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13321373

13331374
DCHECK_EQ(keys.size(), values.size());
13341375
Local<Object> iterable_iterator = Object::New(
1335-
isolate, js_iterator_prototype, keys.data(), values.data(), keys.size());
1376+
isolate, js_iterator_prototype, &keys[0], &values[0], arraysize(keys));
13361377

13371378
auto num_cols_pd = v8::PropertyDescriptor(
13381379
v8::Integer::New(isolate, sqlite3_column_count(stmt->statement_)), false);
13391380
num_cols_pd.set_enumerable(false);
13401381
num_cols_pd.set_configurable(false);
1341-
iterable_iterator
1342-
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1343-
.ToChecked();
1382+
if (iterable_iterator
1383+
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1384+
.IsNothing()) {
1385+
// An error will have been scheduled.
1386+
return;
1387+
}
13441388

13451389
auto stmt_pd =
13461390
v8::PropertyDescriptor(v8::External::New(isolate, stmt), false);
13471391
stmt_pd.set_enumerable(false);
13481392
stmt_pd.set_configurable(false);
1349-
iterable_iterator->DefineProperty(context, env->statement_string(), stmt_pd)
1350-
.ToChecked();
1393+
if (iterable_iterator
1394+
->DefineProperty(context, env->statement_string(), stmt_pd)
1395+
.IsNothing()) {
1396+
// An error will have been scheduled.
1397+
return;
1398+
}
13511399

13521400
auto is_finished_pd =
13531401
v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);
13541402
stmt_pd.set_enumerable(false);
13551403
stmt_pd.set_configurable(false);
1356-
iterable_iterator
1357-
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1358-
.ToChecked();
1404+
if (iterable_iterator
1405+
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1406+
.IsNothing()) {
1407+
// An error will have been scheduled.
1408+
return;
1409+
}
13591410

13601411
args.GetReturnValue().Set(iterable_iterator);
13611412
}

0 commit comments

Comments
 (0)