88#include " node_buffer.h"
99#include " node_errors.h"
1010#include " node_internals.h"
11+ #include " node_process.h"
1112#include " threadpoolwork-inl.h"
1213#include " tracing/traced_value.h"
1314#include " util-inl.h"
@@ -20,6 +21,8 @@ struct node_napi_env__ : public napi_env__ {
2021 CHECK_NOT_NULL (node_env ());
2122 }
2223
24+ ~node_napi_env__ () { FinalizeAll (); }
25+
2326 inline node::Environment* node_env () const {
2427 return node::Environment::GetCurrent (context ());
2528 }
@@ -36,15 +39,55 @@ struct node_napi_env__ : public napi_env__ {
3639 v8::True (isolate));
3740 }
3841
42+ inline void trigger_fatal_exception (v8::Local<v8::Value> local_err) {
43+ v8::Local<v8::Message> local_msg =
44+ v8::Exception::CreateMessage (isolate, local_err);
45+ node::errors::TriggerUncaughtException (isolate, local_err, local_msg);
46+ }
47+
48+ // option enforceUncaughtExceptionPolicy is added for not breaking existing
49+ // running n-api add-ons, and should be deprecated in the next major Node.js
50+ // release.
51+ template <typename T>
52+ inline void CallbackIntoModule (T&& call,
53+ bool enforceUncaughtExceptionPolicy = false ) {
54+ CallIntoModule (
55+ call,
56+ [enforceUncaughtExceptionPolicy](napi_env env_,
57+ v8::Local<v8::Value> local_err) {
58+ node_napi_env__* env = static_cast <node_napi_env__*>(env_);
59+ node::Environment* node_env = env->node_env ();
60+ if (node_env->options ()->no_force_napi_uncaught_exception_policy &&
61+ !enforceUncaughtExceptionPolicy) {
62+ ProcessEmitDeprecationWarning (
63+ node_env,
64+ " Uncaught N-API callback exception detected, please run node "
65+ " without option "
66+ " --no-force-napi-uncaught-exceptions-policy to handle those"
67+ " exceptions properly." ,
68+ " DEP0XXX" );
69+ return ;
70+ }
71+ // If there was an unhandled exception in the complete callback,
72+ // report it as a fatal exception. (There is no JavaScript on the
73+ // callstack that can possibly handle it.)
74+ env->trigger_fatal_exception (local_err);
75+ });
76+ }
77+
3978 void CallFinalizer (napi_finalize cb, void * data, void * hint) override {
79+ CallFinalizer (cb, data, hint, true );
80+ }
81+
82+ inline void CallFinalizer (napi_finalize cb,
83+ void * data,
84+ void * hint,
85+ bool enforceUncaughtExceptionPolicy) {
4086 napi_env env = static_cast <napi_env>(this );
41- node_env ()->SetImmediate ([=](node::Environment* node_env) {
42- v8::HandleScope handle_scope (env->isolate );
43- v8::Context::Scope context_scope (env->context ());
44- env->CallIntoModule ([&](napi_env env) {
45- cb (env, data, hint);
46- });
47- });
87+ v8::HandleScope handle_scope (env->isolate );
88+ v8::Context::Scope context_scope (env->context ());
89+ CallbackIntoModule ([&](napi_env env) { cb (env, data, hint); },
90+ enforceUncaughtExceptionPolicy);
4891 }
4992};
5093
@@ -71,12 +114,9 @@ class BufferFinalizer : private Finalizer {
71114 v8::HandleScope handle_scope (finalizer->_env ->isolate );
72115 v8::Context::Scope context_scope (finalizer->_env ->context ());
73116
74- finalizer->_env ->CallIntoModule ([&](napi_env env) {
75- finalizer->_finalize_callback (
76- env,
77- finalizer->_finalize_data ,
78- finalizer->_finalize_hint );
79- });
117+ finalizer->_env ->CallFinalizer (finalizer->_finalize_callback ,
118+ finalizer->_finalize_data ,
119+ finalizer->_finalize_hint );
80120 });
81121 }
82122
@@ -107,13 +147,6 @@ static inline napi_env NewEnv(v8::Local<v8::Context> context) {
107147 return result;
108148}
109149
110- static inline void trigger_fatal_exception (
111- napi_env env, v8::Local<v8::Value> local_err) {
112- v8::Local<v8::Message> local_msg =
113- v8::Exception::CreateMessage (env->isolate , local_err);
114- node::errors::TriggerUncaughtException (env->isolate , local_err, local_msg);
115- }
116-
117150class ThreadSafeFunction : public node ::AsyncResource {
118151 public:
119152 ThreadSafeFunction (v8::Local<v8::Function> func,
@@ -312,19 +345,16 @@ class ThreadSafeFunction : public node::AsyncResource {
312345 v8::Local<v8::Function>::New (env->isolate , ref);
313346 js_callback = v8impl::JsValueFromV8LocalValue (js_cb);
314347 }
315- env->CallIntoModule ([&](napi_env env) {
316- call_js_cb (env, js_callback, context, data);
317- });
348+ env->CallbackIntoModule (
349+ [&](napi_env env) { call_js_cb (env, js_callback, context, data); });
318350 }
319351 }
320352
321353 void Finalize () {
322354 v8::HandleScope scope (env->isolate );
323355 if (finalize_cb) {
324356 CallbackScope cb_scope (this );
325- env->CallIntoModule ([&](napi_env env) {
326- finalize_cb (env, finalize_data, context);
327- });
357+ env->CallFinalizer (finalize_cb, finalize_data, context, false );
328358 }
329359 EmptyQueueAndDelete ();
330360 }
@@ -693,7 +723,7 @@ napi_status napi_fatal_exception(napi_env env, napi_value err) {
693723 CHECK_ARG (env, err);
694724
695725 v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue (err);
696- v8impl::trigger_fatal_exception (env, local_err);
726+ static_cast <node_napi_env> (env)-> trigger_fatal_exception ( local_err);
697727
698728 return napi_clear_last_error (env);
699729}
@@ -1043,14 +1073,11 @@ class Work : public node::AsyncResource, public node::ThreadPoolWork {
10431073
10441074 CallbackScope callback_scope (this );
10451075
1046- _env->CallIntoModule ([&](napi_env env) {
1047- _complete (env, ConvertUVErrorCode (status), _data);
1048- }, [](napi_env env, v8::Local<v8::Value> local_err) {
1049- // If there was an unhandled exception in the complete callback,
1050- // report it as a fatal exception. (There is no JavaScript on the
1051- // callstack that can possibly handle it.)
1052- v8impl::trigger_fatal_exception (env, local_err);
1053- });
1076+ _env->CallbackIntoModule (
1077+ [&](napi_env env) {
1078+ _complete (env, ConvertUVErrorCode (status), _data);
1079+ },
1080+ true );
10541081
10551082 // Note: Don't access `work` after this point because it was
10561083 // likely deleted by the complete callback.
0 commit comments