Skip to content

Commit 22357ab

Browse files
committed
feat: allow catching all exceptions
1 parent ae2c23e commit 22357ab

File tree

1 file changed

+57
-39
lines changed

1 file changed

+57
-39
lines changed

napi-inl.h

Lines changed: 57 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -79,43 +79,61 @@ inline napi_status AttachData(napi_env env,
7979
// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions
8080
// and rethrow them as JavaScript exceptions before returning from the callback.
8181
template <typename Callable>
82-
inline napi_value WrapCallback(Callable callback) {
83-
#ifdef NAPI_CPP_EXCEPTIONS
82+
inline napi_value WrapCallback(napi_env env, Callable callback) {
83+
#if defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
8484
try {
8585
return callback();
8686
} catch (const Error& e) {
8787
e.ThrowAsJavaScriptException();
8888
return nullptr;
8989
}
90-
#else // NAPI_CPP_EXCEPTIONS
90+
#ifdef NAPI_CPP_EXCEPTIONS_ALL
91+
catch (const std::exception& e) {
92+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
93+
return nullptr;
94+
} catch (...) {
95+
Napi::Error::New(env, "A native exception was thrown")
96+
.ThrowAsJavaScriptException();
97+
return nullptr;
98+
}
99+
#endif // NAPI_CPP_EXCEPTIONS_ALL
100+
#else // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
91101
// When C++ exceptions are disabled, errors are immediately thrown as JS
92102
// exceptions, so there is no need to catch and rethrow them here.
93103
return callback();
94-
#endif // NAPI_CPP_EXCEPTIONS
104+
#endif // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
95105
}
96106

97107
// For use in JS to C++ void callback wrappers to catch any Napi::Error
98108
// exceptions and rethrow them as JavaScript exceptions before returning from
99109
// the callback.
100110
template <typename Callable>
101-
inline void WrapVoidCallback(Callable callback) {
102-
#ifdef NAPI_CPP_EXCEPTIONS
111+
inline void WrapVoidCallback(napi_env env, Callable callback) {
112+
#if defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
103113
try {
104114
callback();
105115
} catch (const Error& e) {
106116
e.ThrowAsJavaScriptException();
107117
}
108-
#else // NAPI_CPP_EXCEPTIONS
118+
#ifdef NAPI_CPP_EXCEPTIONS_ALL
119+
catch (const std::exception& e) {
120+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
121+
} catch (...) {
122+
Napi::Error::New(env, "A native exception was thrown")
123+
.ThrowAsJavaScriptException();
124+
}
125+
#endif // NAPI_CPP_EXCEPTIONS_ALL
126+
#else // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
109127
// When C++ exceptions are disabled, errors are immediately thrown as JS
110128
// exceptions, so there is no need to catch and rethrow them here.
111129
callback();
112-
#endif // NAPI_CPP_EXCEPTIONS
130+
#endif // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
113131
}
114132

115133
template <typename Callable, typename Return>
116134
struct CallbackData {
117135
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
118-
return details::WrapCallback([&] {
136+
return details::WrapCallback(env, [&] {
119137
CallbackInfo callbackInfo(env, info);
120138
CallbackData* callbackData =
121139
static_cast<CallbackData*>(callbackInfo.Data());
@@ -131,7 +149,7 @@ struct CallbackData {
131149
template <typename Callable>
132150
struct CallbackData<Callable, void> {
133151
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
134-
return details::WrapCallback([&] {
152+
return details::WrapCallback(env, [&] {
135153
CallbackInfo callbackInfo(env, info);
136154
CallbackData* callbackData =
137155
static_cast<CallbackData*>(callbackInfo.Data());
@@ -148,7 +166,7 @@ struct CallbackData<Callable, void> {
148166
template <void (*Callback)(const CallbackInfo& info)>
149167
napi_value TemplatedVoidCallback(napi_env env,
150168
napi_callback_info info) NAPI_NOEXCEPT {
151-
return details::WrapCallback([&] {
169+
return details::WrapCallback(env, [&] {
152170
CallbackInfo cbInfo(env, info);
153171
Callback(cbInfo);
154172
return nullptr;
@@ -158,7 +176,7 @@ napi_value TemplatedVoidCallback(napi_env env,
158176
template <Napi::Value (*Callback)(const CallbackInfo& info)>
159177
napi_value TemplatedCallback(napi_env env,
160178
napi_callback_info info) NAPI_NOEXCEPT {
161-
return details::WrapCallback([&] {
179+
return details::WrapCallback(env, [&] {
162180
CallbackInfo cbInfo(env, info);
163181
// MSVC requires to copy 'Callback' function pointer to a local variable
164182
// before invoking it.
@@ -171,7 +189,7 @@ template <typename T,
171189
Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)>
172190
napi_value TemplatedInstanceCallback(napi_env env,
173191
napi_callback_info info) NAPI_NOEXCEPT {
174-
return details::WrapCallback([&] {
192+
return details::WrapCallback(env, [&] {
175193
CallbackInfo cbInfo(env, info);
176194
T* instance = T::Unwrap(cbInfo.This().As<Object>());
177195
return instance ? (instance->*UnwrapCallback)(cbInfo) : Napi::Value();
@@ -181,7 +199,7 @@ napi_value TemplatedInstanceCallback(napi_env env,
181199
template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)>
182200
napi_value TemplatedInstanceVoidCallback(napi_env env, napi_callback_info info)
183201
NAPI_NOEXCEPT {
184-
return details::WrapCallback([&] {
202+
return details::WrapCallback(env, [&] {
185203
CallbackInfo cbInfo(env, info);
186204
T* instance = T::Unwrap(cbInfo.This().As<Object>());
187205
if (instance) (instance->*UnwrapCallback)(cbInfo);
@@ -199,7 +217,7 @@ struct FinalizeData {
199217
static inline void Wrapper(node_addon_api_basic_env env,
200218
void* data,
201219
void* finalizeHint) NAPI_NOEXCEPT {
202-
WrapVoidCallback([&] {
220+
WrapVoidCallback(env, [&] {
203221
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
204222
finalizeData->callback(env, static_cast<T*>(data));
205223
delete finalizeData;
@@ -234,7 +252,7 @@ struct FinalizeData {
234252
static inline void WrapperWithHint(node_addon_api_basic_env env,
235253
void* data,
236254
void* finalizeHint) NAPI_NOEXCEPT {
237-
WrapVoidCallback([&] {
255+
WrapVoidCallback(env, [&] {
238256
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
239257
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
240258
delete finalizeData;
@@ -264,7 +282,7 @@ struct FinalizeData {
264282
static inline void WrapperGCWithoutData(napi_env env,
265283
void* /*data*/,
266284
void* finalizeHint) NAPI_NOEXCEPT {
267-
WrapVoidCallback([&] {
285+
WrapVoidCallback(env, [&] {
268286
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
269287
finalizeData->callback(env);
270288
delete finalizeData;
@@ -274,7 +292,7 @@ struct FinalizeData {
274292
static inline void WrapperGC(napi_env env,
275293
void* data,
276294
void* finalizeHint) NAPI_NOEXCEPT {
277-
WrapVoidCallback([&] {
295+
WrapVoidCallback(env, [&] {
278296
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
279297
finalizeData->callback(env, static_cast<T*>(data));
280298
delete finalizeData;
@@ -284,7 +302,7 @@ struct FinalizeData {
284302
static inline void WrapperGCWithHint(napi_env env,
285303
void* data,
286304
void* finalizeHint) NAPI_NOEXCEPT {
287-
WrapVoidCallback([&] {
305+
WrapVoidCallback(env, [&] {
288306
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
289307
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
290308
delete finalizeData;
@@ -351,7 +369,7 @@ struct ThreadSafeFinalize {
351369
template <typename ContextType, typename DataType, typename CallJs, CallJs call>
352370
inline typename std::enable_if<call != static_cast<CallJs>(nullptr)>::type
353371
CallJsWrapper(napi_env env, napi_value jsCallback, void* context, void* data) {
354-
details::WrapVoidCallback([&]() {
372+
details::WrapVoidCallback(env, [&]() {
355373
call(env,
356374
Function(env, jsCallback),
357375
static_cast<ContextType*>(context),
@@ -365,7 +383,7 @@ CallJsWrapper(napi_env env,
365383
napi_value jsCallback,
366384
void* /*context*/,
367385
void* /*data*/) {
368-
details::WrapVoidCallback([&]() {
386+
details::WrapVoidCallback(env, [&]() {
369387
if (jsCallback != nullptr) {
370388
Function(env, jsCallback).Call(0, nullptr);
371389
}
@@ -399,7 +417,7 @@ template <typename Getter, typename Setter>
399417
struct AccessorCallbackData {
400418
static inline napi_value GetterWrapper(napi_env env,
401419
napi_callback_info info) {
402-
return details::WrapCallback([&] {
420+
return details::WrapCallback(env, [&] {
403421
CallbackInfo callbackInfo(env, info);
404422
AccessorCallbackData* callbackData =
405423
static_cast<AccessorCallbackData*>(callbackInfo.Data());
@@ -410,7 +428,7 @@ struct AccessorCallbackData {
410428

411429
static inline napi_value SetterWrapper(napi_env env,
412430
napi_callback_info info) {
413-
return details::WrapCallback([&] {
431+
return details::WrapCallback(env, [&] {
414432
CallbackInfo callbackInfo(env, info);
415433
AccessorCallbackData* callbackData =
416434
static_cast<AccessorCallbackData*>(callbackInfo.Data());
@@ -501,7 +519,7 @@ class HasBasicFinalizer {
501519
inline napi_value RegisterModule(napi_env env,
502520
napi_value exports,
503521
ModuleRegisterCallback registerCallback) {
504-
return details::WrapCallback([&] {
522+
return details::WrapCallback(env, [&] {
505523
return napi_value(
506524
registerCallback(Napi::Env(env), Napi::Object(env, exports)));
507525
});
@@ -4506,7 +4524,7 @@ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
45064524
template <typename T>
45074525
inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
45084526
napi_env env, napi_callback_info info) {
4509-
return details::WrapCallback([&] {
4527+
return details::WrapCallback(env, [&] {
45104528
CallbackInfo callbackInfo(env, info);
45114529
InstanceVoidMethodCallbackData* callbackData =
45124530
reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
@@ -4521,7 +4539,7 @@ inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
45214539
template <typename T>
45224540
inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
45234541
napi_env env, napi_callback_info info) {
4524-
return details::WrapCallback([&] {
4542+
return details::WrapCallback(env, [&] {
45254543
CallbackInfo callbackInfo(env, info);
45264544
InstanceMethodCallbackData* callbackData =
45274545
reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
@@ -4535,7 +4553,7 @@ inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
45354553
template <typename T>
45364554
inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
45374555
napi_env env, napi_callback_info info) {
4538-
return details::WrapCallback([&] {
4556+
return details::WrapCallback(env, [&] {
45394557
CallbackInfo callbackInfo(env, info);
45404558
InstanceAccessorCallbackData* callbackData =
45414559
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
@@ -4549,7 +4567,7 @@ inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
45494567
template <typename T>
45504568
inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper(
45514569
napi_env env, napi_callback_info info) {
4552-
return details::WrapCallback([&] {
4570+
return details::WrapCallback(env, [&] {
45534571
CallbackInfo callbackInfo(env, info);
45544572
InstanceAccessorCallbackData* callbackData =
45554573
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
@@ -4565,7 +4583,7 @@ template <typename T>
45654583
template <typename InstanceWrap<T>::InstanceSetterCallback method>
45664584
inline napi_value InstanceWrap<T>::WrappedMethod(
45674585
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
4568-
return details::WrapCallback([&] {
4586+
return details::WrapCallback(env, [&] {
45694587
const CallbackInfo cbInfo(env, info);
45704588
T* instance = T::Unwrap(cbInfo.This().As<Object>());
45714589
if (instance) (instance->*method)(cbInfo, cbInfo[0]);
@@ -4960,10 +4978,10 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
49604978
bool isConstructCall = (new_target != nullptr);
49614979
if (!isConstructCall) {
49624980
return details::WrapCallback(
4963-
[&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
4981+
env, [&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
49644982
}
49654983

4966-
napi_value wrapper = details::WrapCallback([&] {
4984+
napi_value wrapper = details::WrapCallback(env, [&] {
49674985
CallbackInfo callbackInfo(env, info);
49684986
T* instance = new T(callbackInfo);
49694987
#ifdef NAPI_CPP_EXCEPTIONS
@@ -4987,7 +5005,7 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
49875005
template <typename T>
49885006
inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
49895007
napi_env env, napi_callback_info info) {
4990-
return details::WrapCallback([&] {
5008+
return details::WrapCallback(env, [&] {
49915009
CallbackInfo callbackInfo(env, info);
49925010
StaticVoidMethodCallbackData* callbackData =
49935011
reinterpret_cast<StaticVoidMethodCallbackData*>(callbackInfo.Data());
@@ -5000,7 +5018,7 @@ inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
50005018
template <typename T>
50015019
inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
50025020
napi_env env, napi_callback_info info) {
5003-
return details::WrapCallback([&] {
5021+
return details::WrapCallback(env, [&] {
50045022
CallbackInfo callbackInfo(env, info);
50055023
StaticMethodCallbackData* callbackData =
50065024
reinterpret_cast<StaticMethodCallbackData*>(callbackInfo.Data());
@@ -5012,7 +5030,7 @@ inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
50125030
template <typename T>
50135031
inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
50145032
napi_env env, napi_callback_info info) {
5015-
return details::WrapCallback([&] {
5033+
return details::WrapCallback(env, [&] {
50165034
CallbackInfo callbackInfo(env, info);
50175035
StaticAccessorCallbackData* callbackData =
50185036
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
@@ -5024,7 +5042,7 @@ inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
50245042
template <typename T>
50255043
inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
50265044
napi_env env, napi_callback_info info) {
5027-
return details::WrapCallback([&] {
5045+
return details::WrapCallback(env, [&] {
50285046
CallbackInfo callbackInfo(env, info);
50295047
StaticAccessorCallbackData* callbackData =
50305048
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
@@ -5097,7 +5115,7 @@ template <typename T>
50975115
template <typename ObjectWrap<T>::StaticSetterCallback method>
50985116
inline napi_value ObjectWrap<T>::WrappedMethod(
50995117
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
5100-
return details::WrapCallback([&] {
5118+
return details::WrapCallback(env, [&] {
51015119
const CallbackInfo cbInfo(env, info);
51025120
// MSVC requires to copy 'method' function pointer to a local variable
51035121
// before invoking it.
@@ -5415,10 +5433,10 @@ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
54155433
AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
54165434
self->OnWorkComplete(env, status);
54175435
}
5418-
inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
5436+
inline void AsyncWorker::OnWorkComplete(Napi::Env env, napi_status status) {
54195437
if (status != napi_cancelled) {
54205438
HandleScope scope(_env);
5421-
details::WrapCallback([&] {
5439+
details::WrapCallback(env, [&] {
54225440
if (_error.size() == 0) {
54235441
OnOK();
54245442
} else {
@@ -6330,7 +6348,7 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
63306348
return;
63316349
}
63326350

6333-
details::WrapVoidCallback([&]() {
6351+
details::WrapVoidCallback(env, [&]() {
63346352
if (data != nullptr) {
63356353
auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
63366354
(*callbackWrapper)(env, Function(env, jsCallback));

0 commit comments

Comments
 (0)