diff --git a/src/macros.h b/src/macros.h index 3bcde83c..0f2a03c8 100644 --- a/src/macros.h +++ b/src/macros.h @@ -4,9 +4,14 @@ const char* sqlite_code_string(int code); const char* sqlite_authorizer_string(int type); #include +#include // TODO: better way to work around StringConcat? #include + +// Forward declaration of shutdown flag from node_sqlite3.cc +extern std::atomic g_env_shutting_down; + inline Napi::String StringConcat(Napi::Value str1, Napi::Value str2) { return Napi::String::New(str1.Env(), str1.As().Utf8Value() + str2.As().Utf8Value() ); @@ -128,8 +133,21 @@ inline bool OtherIsInt(Napi::Number source) { if ((argc != 0) && (passed_argv != NULL)) {\ args.assign(passed_argv, passed_argv + argc);\ }\ - Napi::Value res = (callback).Call(Napi::Value(context), args); \ - if (res.IsEmpty()) return __VA_ARGS__; + try {\ + Napi::Value res = (callback).Call(Napi::Value(context), args);\ + if (res.IsEmpty()) return __VA_ARGS__;\ + } catch (const Napi::Error&) {\ + /* During Node.js/Electron shutdown, when using NAPI_CPP_EXCEPTIONS,*/\ + /* we must take care to not throw any exceptions. */\ + /* But when napi_call_function returns napi_cannot_run_js */\ + /* this throws a C++ exception, when NAPI_CPP_EXCEPTIONS is enabled. */\ + if (g_env_shutting_down.load()) {\ + /* We need to silently ignore exceptions during shutdown. */\ + return __VA_ARGS__;\ + }\ + /* Real rror - re-throw to propagate it */\ + throw;\ + } #define WORK_DEFINITION(name) \ Napi::Value name(const Napi::CallbackInfo& info); \ @@ -204,4 +222,4 @@ inline bool OtherIsInt(Napi::Number source) { backup->Process(); \ backup->db->Process(); -#endif \ No newline at end of file +#endif diff --git a/src/node_sqlite3.cc b/src/node_sqlite3.cc index 6f47a68a..a566ee73 100644 --- a/src/node_sqlite3.cc +++ b/src/node_sqlite3.cc @@ -2,6 +2,7 @@ #include #include #include +#include #include #include "macros.h" @@ -11,11 +12,21 @@ using namespace node_sqlite3; +// Global flag set when the environment is shutting down. +std::atomic g_env_shutting_down{false}; + +static void EnvCleanupHook(void* /*data*/) { + g_env_shutting_down.store(true); +} + namespace { Napi::Object RegisterModule(Napi::Env env, Napi::Object exports) { Napi::HandleScope scope(env); + // Register cleanup hook to detect shutdown + napi_add_env_cleanup_hook(env, EnvCleanupHook, nullptr); + Database::Init(env, exports); Statement::Init(env, exports); Backup::Init(env, exports);