Skip to content

Commit f41bc4c

Browse files
jasnellRafaelGSS
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 027749e commit f41bc4c

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
@@ -120,13 +120,15 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
120120
const char* errstr = sqlite3_errstr(errcode);
121121

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

132134
class UserDefinedFunction {
@@ -755,12 +757,14 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
755757
}
756758
}
757759

758-
Local<String> db_key =
759-
String::NewFromUtf8(env->isolate(), "db", NewStringType::kNormal)
760-
.ToLocalChecked();
760+
Local<String> db_key = FIXED_ONE_BYTE_STRING(env->isolate(), "db");
761+
761762
if (options->HasOwnProperty(env->context(), db_key).FromJust()) {
762-
Local<Value> db_value =
763-
options->Get(env->context(), db_key).ToLocalChecked();
763+
Local<Value> db_value;
764+
if (!options->Get(env->context(), db_key).ToLocal(&db_value)) {
765+
// An error will have been scheduled.
766+
return;
767+
}
764768
if (db_value->IsString()) {
765769
String::Utf8Value str(env->isolate(), db_value);
766770
db_name = std::string(*str);
@@ -829,8 +833,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
829833
}
830834

831835
Local<Object> options = args[1].As<Object>();
832-
Local<Value> conflictValue =
833-
options->Get(env->context(), env->onconflict_string()).ToLocalChecked();
836+
Local<Value> conflictValue;
837+
if (!options->Get(env->context(), env->onconflict_string())
838+
.ToLocal(&conflictValue)) {
839+
// An error will have been scheduled.
840+
return;
841+
}
834842

835843
if (!conflictValue->IsUndefined()) {
836844
if (!conflictValue->IsFunction()) {
@@ -858,8 +866,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
858866

859867
if (options->HasOwnProperty(env->context(), env->filter_string())
860868
.FromJust()) {
861-
Local<Value> filterValue =
862-
options->Get(env->context(), env->filter_string()).ToLocalChecked();
869+
Local<Value> filterValue;
870+
if (!options->Get(env->context(), env->filter_string())
871+
.ToLocal(&filterValue)) {
872+
// An error will have been scheduled.
873+
return;
874+
}
863875

864876
if (!filterValue->IsFunction()) {
865877
THROW_ERR_INVALID_ARG_TYPE(
@@ -871,6 +883,10 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
871883
Local<Function> filterFunc = filterValue.As<Function>();
872884

873885
filterCallback = [env, filterFunc](std::string item) -> bool {
886+
// TODO(@jasnell): The use of ToLocalChecked here means that if
887+
// the filter function throws an error the process will crash.
888+
// The filterCallback should be updated to avoid the check and
889+
// propagate the error correctly.
874890
Local<Value> argv[] = {String::NewFromUtf8(env->isolate(),
875891
item.c_str(),
876892
NewStringType::kNormal)
@@ -1240,11 +1256,18 @@ void StatementSync::IterateReturnCallback(
12401256

12411257
auto self = args.This();
12421258
// iterator has fetch all result or break, prevent next func to return result
1243-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1244-
.ToChecked();
1259+
if (self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1260+
.IsNothing()) {
1261+
// An error will have been scheduled.
1262+
return;
1263+
}
12451264

1246-
auto external_stmt = Local<External>::Cast(
1247-
self->Get(context, env->statement_string()).ToLocalChecked());
1265+
Local<Value> val;
1266+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1267+
// An error will have been scheduled.
1268+
return;
1269+
}
1270+
auto external_stmt = Local<External>::Cast(val);
12481271
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
12491272
if (!stmt->IsFinalized()) {
12501273
sqlite3_reset(stmt->statement_);
@@ -1268,28 +1291,38 @@ void StatementSync::IterateNextCallback(
12681291

12691292
auto self = args.This();
12701293

1294+
Local<Value> val;
1295+
if (!self->Get(context, env->isfinished_string()).ToLocal(&val)) {
1296+
// An error will have been scheduled.
1297+
return;
1298+
}
1299+
12711300
// skip iteration if is_finished
1272-
auto is_finished = Local<Boolean>::Cast(
1273-
self->Get(context, env->isfinished_string()).ToLocalChecked());
1301+
auto is_finished = Local<Boolean>::Cast(val);
12741302
if (is_finished->Value()) {
1275-
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
1276-
LocalVector<Value> values(isolate,
1277-
{Boolean::New(isolate, true), Null(isolate)});
1278-
1279-
DCHECK_EQ(keys.size(), values.size());
1303+
Local<Name> keys[] = {env->done_string(), env->value_string()};
1304+
Local<Value> values[] = {Boolean::New(isolate, true), Null(isolate)};
1305+
static_assert(arraysize(keys) == arraysize(values));
12801306
Local<Object> result = Object::New(
1281-
isolate, Null(isolate), keys.data(), values.data(), keys.size());
1307+
isolate, Null(isolate), &keys[0], &values[0], arraysize(keys));
12821308
args.GetReturnValue().Set(result);
12831309
return;
12841310
}
12851311

1286-
auto external_stmt = Local<External>::Cast(
1287-
self->Get(context, env->statement_string()).ToLocalChecked());
1312+
if (!self->Get(context, env->statement_string()).ToLocal(&val)) {
1313+
// An error will have been scheduled.
1314+
return;
1315+
}
1316+
1317+
auto external_stmt = Local<External>::Cast(val);
12881318
auto stmt = static_cast<StatementSync*>(external_stmt->Value());
1289-
auto num_cols =
1290-
Local<Integer>::Cast(
1291-
self->Get(context, env->num_cols_string()).ToLocalChecked())
1292-
->Value();
1319+
1320+
if (!self->Get(context, env->num_cols_string()).ToLocal(&val)) {
1321+
// An error will have been scheduled.
1322+
return;
1323+
}
1324+
1325+
auto num_cols = Local<Integer>::Cast(val)->Value();
12931326

12941327
THROW_AND_RETURN_ON_BAD_STATE(
12951328
env, stmt->IsFinalized(), "statement has been finalized");
@@ -1301,8 +1334,12 @@ void StatementSync::IterateNextCallback(
13011334

13021335
// cleanup when no more rows to fetch
13031336
sqlite3_reset(stmt->statement_);
1304-
self->Set(context, env->isfinished_string(), Boolean::New(isolate, true))
1305-
.ToChecked();
1337+
if (self->Set(
1338+
context, env->isfinished_string(), Boolean::New(isolate, true))
1339+
.IsNothing()) {
1340+
// An error would have been scheduled
1341+
return;
1342+
}
13061343

13071344
LocalVector<Name> keys(isolate, {env->done_string(), env->value_string()});
13081345
LocalVector<Value> values(isolate,
@@ -1356,15 +1393,19 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13561393
return;
13571394
}
13581395

1359-
Local<Function> next_func =
1360-
Function::New(context, StatementSync::IterateNextCallback)
1361-
.ToLocalChecked();
1362-
Local<Function> return_func =
1363-
Function::New(context, StatementSync::IterateReturnCallback)
1364-
.ToLocalChecked();
1396+
Local<Function> next_func;
1397+
Local<Function> return_func;
1398+
if (!Function::New(context, StatementSync::IterateNextCallback)
1399+
.ToLocal(&next_func) ||
1400+
!Function::New(context, StatementSync::IterateReturnCallback)
1401+
.ToLocal(&return_func)) {
1402+
// An error will have been scheduled.
1403+
return;
1404+
}
13651405

1366-
LocalVector<Name> keys(isolate, {env->next_string(), env->return_string()});
1367-
LocalVector<Value> values(isolate, {next_func, return_func});
1406+
Local<Name> keys[] = {env->next_string(), env->return_string()};
1407+
Local<Value> values[] = {next_func, return_func};
1408+
static_assert(arraysize(keys) == arraysize(values));
13681409

13691410
Local<Object> global = context->Global();
13701411
Local<Value> js_iterator;
@@ -1376,32 +1417,41 @@ void StatementSync::Iterate(const FunctionCallbackInfo<Value>& args) {
13761417
.ToLocal(&js_iterator_prototype))
13771418
return;
13781419

1379-
DCHECK_EQ(keys.size(), values.size());
13801420
Local<Object> iterable_iterator = Object::New(
1381-
isolate, js_iterator_prototype, keys.data(), values.data(), keys.size());
1421+
isolate, js_iterator_prototype, &keys[0], &values[0], arraysize(keys));
13821422

13831423
auto num_cols_pd = v8::PropertyDescriptor(
13841424
v8::Integer::New(isolate, sqlite3_column_count(stmt->statement_)), false);
13851425
num_cols_pd.set_enumerable(false);
13861426
num_cols_pd.set_configurable(false);
1387-
iterable_iterator
1388-
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1389-
.ToChecked();
1427+
if (iterable_iterator
1428+
->DefineProperty(context, env->num_cols_string(), num_cols_pd)
1429+
.IsNothing()) {
1430+
// An error will have been scheduled.
1431+
return;
1432+
}
13901433

13911434
auto stmt_pd =
13921435
v8::PropertyDescriptor(v8::External::New(isolate, stmt), false);
13931436
stmt_pd.set_enumerable(false);
13941437
stmt_pd.set_configurable(false);
1395-
iterable_iterator->DefineProperty(context, env->statement_string(), stmt_pd)
1396-
.ToChecked();
1438+
if (iterable_iterator
1439+
->DefineProperty(context, env->statement_string(), stmt_pd)
1440+
.IsNothing()) {
1441+
// An error will have been scheduled.
1442+
return;
1443+
}
13971444

13981445
auto is_finished_pd =
13991446
v8::PropertyDescriptor(v8::Boolean::New(isolate, false), true);
14001447
stmt_pd.set_enumerable(false);
14011448
stmt_pd.set_configurable(false);
1402-
iterable_iterator
1403-
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1404-
.ToChecked();
1449+
if (iterable_iterator
1450+
->DefineProperty(context, env->isfinished_string(), is_finished_pd)
1451+
.IsNothing()) {
1452+
// An error will have been scheduled.
1453+
return;
1454+
}
14051455

14061456
args.GetReturnValue().Set(iterable_iterator);
14071457
}

0 commit comments

Comments
 (0)