Skip to content

Commit fc130ef

Browse files
committed
feat: allow catching all exceptions
1 parent 600fe6c commit fc130ef

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
@@ -78,43 +78,61 @@ inline napi_status AttachData(napi_env env,
7878
// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions
7979
// and rethrow them as JavaScript exceptions before returning from the callback.
8080
template <typename Callable>
81-
inline napi_value WrapCallback(Callable callback) {
82-
#ifdef NAPI_CPP_EXCEPTIONS
81+
inline napi_value WrapCallback(napi_env env, Callable callback) {
82+
#if defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
8383
try {
8484
return callback();
8585
} catch (const Error& e) {
8686
e.ThrowAsJavaScriptException();
8787
return nullptr;
8888
}
89-
#else // NAPI_CPP_EXCEPTIONS
89+
#ifdef NAPI_CPP_EXCEPTIONS_ALL
90+
catch (const std::exception& e) {
91+
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
92+
return nullptr;
93+
} catch (...) {
94+
Napi::Error::New(env, "A native exception was thrown")
95+
.ThrowAsJavaScriptException();
96+
return nullptr;
97+
}
98+
#endif // NAPI_CPP_EXCEPTIONS_ALL
99+
#else // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
90100
// When C++ exceptions are disabled, errors are immediately thrown as JS
91101
// exceptions, so there is no need to catch and rethrow them here.
92102
return callback();
93-
#endif // NAPI_CPP_EXCEPTIONS
103+
#endif // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
94104
}
95105

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

114132
template <typename Callable, typename Return>
115133
struct CallbackData {
116134
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
117-
return details::WrapCallback([&] {
135+
return details::WrapCallback(env, [&] {
118136
CallbackInfo callbackInfo(env, info);
119137
CallbackData* callbackData =
120138
static_cast<CallbackData*>(callbackInfo.Data());
@@ -130,7 +148,7 @@ struct CallbackData {
130148
template <typename Callable>
131149
struct CallbackData<Callable, void> {
132150
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
133-
return details::WrapCallback([&] {
151+
return details::WrapCallback(env, [&] {
134152
CallbackInfo callbackInfo(env, info);
135153
CallbackData* callbackData =
136154
static_cast<CallbackData*>(callbackInfo.Data());
@@ -147,7 +165,7 @@ struct CallbackData<Callable, void> {
147165
template <void (*Callback)(const CallbackInfo& info)>
148166
napi_value TemplatedVoidCallback(napi_env env,
149167
napi_callback_info info) NAPI_NOEXCEPT {
150-
return details::WrapCallback([&] {
168+
return details::WrapCallback(env, [&] {
151169
CallbackInfo cbInfo(env, info);
152170
Callback(cbInfo);
153171
return nullptr;
@@ -157,7 +175,7 @@ napi_value TemplatedVoidCallback(napi_env env,
157175
template <Napi::Value (*Callback)(const CallbackInfo& info)>
158176
napi_value TemplatedCallback(napi_env env,
159177
napi_callback_info info) NAPI_NOEXCEPT {
160-
return details::WrapCallback([&] {
178+
return details::WrapCallback(env, [&] {
161179
CallbackInfo cbInfo(env, info);
162180
// MSVC requires to copy 'Callback' function pointer to a local variable
163181
// before invoking it.
@@ -170,7 +188,7 @@ template <typename T,
170188
Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)>
171189
napi_value TemplatedInstanceCallback(napi_env env,
172190
napi_callback_info info) NAPI_NOEXCEPT {
173-
return details::WrapCallback([&] {
191+
return details::WrapCallback(env, [&] {
174192
CallbackInfo cbInfo(env, info);
175193
T* instance = T::Unwrap(cbInfo.This().As<Object>());
176194
return instance ? (instance->*UnwrapCallback)(cbInfo) : Napi::Value();
@@ -180,7 +198,7 @@ napi_value TemplatedInstanceCallback(napi_env env,
180198
template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)>
181199
napi_value TemplatedInstanceVoidCallback(napi_env env, napi_callback_info info)
182200
NAPI_NOEXCEPT {
183-
return details::WrapCallback([&] {
201+
return details::WrapCallback(env, [&] {
184202
CallbackInfo cbInfo(env, info);
185203
T* instance = T::Unwrap(cbInfo.This().As<Object>());
186204
if (instance) (instance->*UnwrapCallback)(cbInfo);
@@ -198,7 +216,7 @@ struct FinalizeData {
198216
static inline void Wrapper(node_api_nogc_env env,
199217
void* data,
200218
void* finalizeHint) NAPI_NOEXCEPT {
201-
WrapVoidCallback([&] {
219+
WrapVoidCallback(env, [&] {
202220
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
203221
finalizeData->callback(env, static_cast<T*>(data));
204222
delete finalizeData;
@@ -228,7 +246,7 @@ struct FinalizeData {
228246
static inline void WrapperWithHint(node_api_nogc_env env,
229247
void* data,
230248
void* finalizeHint) NAPI_NOEXCEPT {
231-
WrapVoidCallback([&] {
249+
WrapVoidCallback(env, [&] {
232250
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
233251
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
234252
delete finalizeData;
@@ -253,7 +271,7 @@ struct FinalizeData {
253271
static inline void WrapperGCWithoutData(napi_env env,
254272
void* /*data*/,
255273
void* finalizeHint) NAPI_NOEXCEPT {
256-
WrapVoidCallback([&] {
274+
WrapVoidCallback(env, [&] {
257275
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
258276
finalizeData->callback(env);
259277
delete finalizeData;
@@ -263,7 +281,7 @@ struct FinalizeData {
263281
static inline void WrapperGC(napi_env env,
264282
void* data,
265283
void* finalizeHint) NAPI_NOEXCEPT {
266-
WrapVoidCallback([&] {
284+
WrapVoidCallback(env, [&] {
267285
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
268286
finalizeData->callback(env, static_cast<T*>(data));
269287
delete finalizeData;
@@ -273,7 +291,7 @@ struct FinalizeData {
273291
static inline void WrapperGCWithHint(napi_env env,
274292
void* data,
275293
void* finalizeHint) NAPI_NOEXCEPT {
276-
WrapVoidCallback([&] {
294+
WrapVoidCallback(env, [&] {
277295
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
278296
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
279297
delete finalizeData;
@@ -340,7 +358,7 @@ struct ThreadSafeFinalize {
340358
template <typename ContextType, typename DataType, typename CallJs, CallJs call>
341359
inline typename std::enable_if<call != static_cast<CallJs>(nullptr)>::type
342360
CallJsWrapper(napi_env env, napi_value jsCallback, void* context, void* data) {
343-
details::WrapVoidCallback([&]() {
361+
details::WrapVoidCallback(env, [&]() {
344362
call(env,
345363
Function(env, jsCallback),
346364
static_cast<ContextType*>(context),
@@ -354,7 +372,7 @@ CallJsWrapper(napi_env env,
354372
napi_value jsCallback,
355373
void* /*context*/,
356374
void* /*data*/) {
357-
details::WrapVoidCallback([&]() {
375+
details::WrapVoidCallback(env, [&]() {
358376
if (jsCallback != nullptr) {
359377
Function(env, jsCallback).Call(0, nullptr);
360378
}
@@ -388,7 +406,7 @@ template <typename Getter, typename Setter>
388406
struct AccessorCallbackData {
389407
static inline napi_value GetterWrapper(napi_env env,
390408
napi_callback_info info) {
391-
return details::WrapCallback([&] {
409+
return details::WrapCallback(env, [&] {
392410
CallbackInfo callbackInfo(env, info);
393411
AccessorCallbackData* callbackData =
394412
static_cast<AccessorCallbackData*>(callbackInfo.Data());
@@ -399,7 +417,7 @@ struct AccessorCallbackData {
399417

400418
static inline napi_value SetterWrapper(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());
@@ -490,7 +508,7 @@ class HasBasicFinalizer {
490508
inline napi_value RegisterModule(napi_env env,
491509
napi_value exports,
492510
ModuleRegisterCallback registerCallback) {
493-
return details::WrapCallback([&] {
511+
return details::WrapCallback(env, [&] {
494512
return napi_value(
495513
registerCallback(Napi::Env(env), Napi::Object(env, exports)));
496514
});
@@ -4479,7 +4497,7 @@ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
44794497
template <typename T>
44804498
inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
44814499
napi_env env, napi_callback_info info) {
4482-
return details::WrapCallback([&] {
4500+
return details::WrapCallback(env, [&] {
44834501
CallbackInfo callbackInfo(env, info);
44844502
InstanceVoidMethodCallbackData* callbackData =
44854503
reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
@@ -4494,7 +4512,7 @@ inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
44944512
template <typename T>
44954513
inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
44964514
napi_env env, napi_callback_info info) {
4497-
return details::WrapCallback([&] {
4515+
return details::WrapCallback(env, [&] {
44984516
CallbackInfo callbackInfo(env, info);
44994517
InstanceMethodCallbackData* callbackData =
45004518
reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
@@ -4508,7 +4526,7 @@ inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
45084526
template <typename T>
45094527
inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
45104528
napi_env env, napi_callback_info info) {
4511-
return details::WrapCallback([&] {
4529+
return details::WrapCallback(env, [&] {
45124530
CallbackInfo callbackInfo(env, info);
45134531
InstanceAccessorCallbackData* callbackData =
45144532
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
@@ -4522,7 +4540,7 @@ inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
45224540
template <typename T>
45234541
inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper(
45244542
napi_env env, napi_callback_info info) {
4525-
return details::WrapCallback([&] {
4543+
return details::WrapCallback(env, [&] {
45264544
CallbackInfo callbackInfo(env, info);
45274545
InstanceAccessorCallbackData* callbackData =
45284546
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
@@ -4538,7 +4556,7 @@ template <typename T>
45384556
template <typename InstanceWrap<T>::InstanceSetterCallback method>
45394557
inline napi_value InstanceWrap<T>::WrappedMethod(
45404558
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
4541-
return details::WrapCallback([&] {
4559+
return details::WrapCallback(env, [&] {
45424560
const CallbackInfo cbInfo(env, info);
45434561
T* instance = T::Unwrap(cbInfo.This().As<Object>());
45444562
if (instance) (instance->*method)(cbInfo, cbInfo[0]);
@@ -4933,10 +4951,10 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
49334951
bool isConstructCall = (new_target != nullptr);
49344952
if (!isConstructCall) {
49354953
return details::WrapCallback(
4936-
[&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
4954+
env, [&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
49374955
}
49384956

4939-
napi_value wrapper = details::WrapCallback([&] {
4957+
napi_value wrapper = details::WrapCallback(env, [&] {
49404958
CallbackInfo callbackInfo(env, info);
49414959
T* instance = new T(callbackInfo);
49424960
#ifdef NAPI_CPP_EXCEPTIONS
@@ -4960,7 +4978,7 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
49604978
template <typename T>
49614979
inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
49624980
napi_env env, napi_callback_info info) {
4963-
return details::WrapCallback([&] {
4981+
return details::WrapCallback(env, [&] {
49644982
CallbackInfo callbackInfo(env, info);
49654983
StaticVoidMethodCallbackData* callbackData =
49664984
reinterpret_cast<StaticVoidMethodCallbackData*>(callbackInfo.Data());
@@ -4973,7 +4991,7 @@ inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
49734991
template <typename T>
49744992
inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
49754993
napi_env env, napi_callback_info info) {
4976-
return details::WrapCallback([&] {
4994+
return details::WrapCallback(env, [&] {
49774995
CallbackInfo callbackInfo(env, info);
49784996
StaticMethodCallbackData* callbackData =
49794997
reinterpret_cast<StaticMethodCallbackData*>(callbackInfo.Data());
@@ -4985,7 +5003,7 @@ inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
49855003
template <typename T>
49865004
inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
49875005
napi_env env, napi_callback_info info) {
4988-
return details::WrapCallback([&] {
5006+
return details::WrapCallback(env, [&] {
49895007
CallbackInfo callbackInfo(env, info);
49905008
StaticAccessorCallbackData* callbackData =
49915009
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
@@ -4997,7 +5015,7 @@ inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
49975015
template <typename T>
49985016
inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
49995017
napi_env env, napi_callback_info info) {
5000-
return details::WrapCallback([&] {
5018+
return details::WrapCallback(env, [&] {
50015019
CallbackInfo callbackInfo(env, info);
50025020
StaticAccessorCallbackData* callbackData =
50035021
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
@@ -5066,7 +5084,7 @@ template <typename T>
50665084
template <typename ObjectWrap<T>::StaticSetterCallback method>
50675085
inline napi_value ObjectWrap<T>::WrappedMethod(
50685086
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
5069-
return details::WrapCallback([&] {
5087+
return details::WrapCallback(env, [&] {
50705088
const CallbackInfo cbInfo(env, info);
50715089
// MSVC requires to copy 'method' function pointer to a local variable
50725090
// before invoking it.
@@ -5384,10 +5402,10 @@ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
53845402
AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
53855403
self->OnWorkComplete(env, status);
53865404
}
5387-
inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
5405+
inline void AsyncWorker::OnWorkComplete(Napi::Env env, napi_status status) {
53885406
if (status != napi_cancelled) {
53895407
HandleScope scope(_env);
5390-
details::WrapCallback([&] {
5408+
details::WrapCallback(env, [&] {
53915409
if (_error.size() == 0) {
53925410
OnOK();
53935411
} else {
@@ -6299,7 +6317,7 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
62996317
return;
63006318
}
63016319

6302-
details::WrapVoidCallback([&]() {
6320+
details::WrapVoidCallback(env, [&]() {
63036321
if (data != nullptr) {
63046322
auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
63056323
(*callbackWrapper)(env, Function(env, jsCallback));

0 commit comments

Comments
 (0)