diff --git a/src/js_native_api_v8.cc b/src/js_native_api_v8.cc index abc9e56d6b0bbb..b96f8da85002f7 100644 --- a/src/js_native_api_v8.cc +++ b/src/js_native_api_v8.cc @@ -308,6 +308,9 @@ class CallbackWrapperBase : public CallbackWrapper { env->CallIntoModule([&](napi_env env) { result = cb(env, cbinfo_wrapper); }, [&](napi_env env, v8::Local value) { exceptionOccurred = true; + if (env->terminatedOrTerminating()) { + return; + } env->isolate->ThrowException(value); }); diff --git a/src/js_native_api_v8.h b/src/js_native_api_v8.h index 766398744c5dfb..c4fd883132822d 100644 --- a/src/js_native_api_v8.h +++ b/src/js_native_api_v8.h @@ -72,9 +72,20 @@ struct napi_env__ { } static inline void HandleThrow(napi_env env, v8::Local value) { + if (env->terminatedOrTerminating()) { + return; + } env->isolate->ThrowException(value); } + // i.e. whether v8 exited or is about to exit + inline bool terminatedOrTerminating() { + return this->isolate->IsExecutionTerminating() || !can_call_into_js(); + } + + // v8 uses a special exception to indicate termination, the + // `handle_exception` callback should identify such case using + // terminatedOrTerminating() before actually handle the exception template inline void CallIntoModule(T&& call, U&& handle_exception = HandleThrow) { int open_handle_scopes_before = open_handle_scopes; diff --git a/src/node_api.cc b/src/node_api.cc index 8f1e4fb0e40d4a..08373dcabb1f40 100644 --- a/src/node_api.cc +++ b/src/node_api.cc @@ -82,6 +82,9 @@ template void node_napi_env__::CallbackIntoModule(T&& call) { CallIntoModule(call, [](napi_env env_, v8::Local local_err) { node_napi_env__* env = static_cast(env_); + if (env->terminatedOrTerminating()) { + return; + } node::Environment* node_env = env->node_env(); if (!node_env->options()->force_node_api_uncaught_exceptions_policy && !enforceUncaughtExceptionPolicy) {