src: improve error handling in node_sqlite · nodejs/node@d6cf091
@@ -126,13 +126,15 @@ inline void THROW_ERR_SQLITE_ERROR(Isolate* isolate, int errcode) {
126126const char* errstr = sqlite3_errstr(errcode);
127127128128 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}
137139138140UserDefinedFunction::UserDefinedFunction(Environment* env,
@@ -734,12 +736,14 @@ void DatabaseSync::CreateSession(const FunctionCallbackInfo<Value>& args) {
734736 }
735737 }
736738737- 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+740741if (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+ }
743747if (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 }
809813810814 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+ }
813821814822if (!conflictValue->IsUndefined()) {
815823if (!conflictValue->IsFunction()) {
@@ -837,8 +845,12 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
837845838846if (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+ }
842854843855if (!filterValue->IsFunction()) {
844856THROW_ERR_INVALID_ARG_TYPE(
@@ -850,6 +862,10 @@ void DatabaseSync::ApplyChangeset(const FunctionCallbackInfo<Value>& args) {
850862 Local<Function> filterFunc = filterValue.As<Function>();
851863852864 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(
1214123012151231auto 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+ }
121912381220-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);
12221245auto stmt = static_cast<StatementSync*>(external_stmt->Value());
12231246if (!stmt->IsFinalized()) {
12241247sqlite3_reset(stmt->statement_);
@@ -1242,28 +1265,38 @@ void StatementSync::IterateNextCallback(
1242126512431266auto self = args.This();
124412671268+ 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);
12481276if (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);
12571283return;
12581284 }
125912851260-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);
12621292auto 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();
1267130012681301THROW_AND_RETURN_ON_BAD_STATE(
12691302 env, stmt->IsFinalized(), "statement has been finalized");
@@ -1275,8 +1308,12 @@ void StatementSync::IterateNextCallback(
1275130812761309// cleanup when no more rows to fetch
12771310sqlite3_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+ }
1280131712811318 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) {
13291366return;
13301367 }
133113681332- 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+ }
133813781339- 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));
1341138213421383 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))
13501391return;
135113921352-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));
1355139513561396auto num_cols_pd = v8::PropertyDescriptor(
13571397v8::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+ }
1363140613641407auto stmt_pd =
13651408v8::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+ }
1370141713711418auto is_finished_pd =
13721419v8::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+ }
1378142813791429 args.GetReturnValue().Set(iterable_iterator);
13801430}