Skip to content

Commit

Permalink
feat: allow catching all exceptions
Browse files Browse the repository at this point in the history
  • Loading branch information
KevinEady committed Oct 18, 2024
1 parent 600fe6c commit fc130ef
Showing 1 changed file with 57 additions and 39 deletions.
96 changes: 57 additions & 39 deletions napi-inl.h
Original file line number Diff line number Diff line change
Expand Up @@ -78,43 +78,61 @@ inline napi_status AttachData(napi_env env,
// For use in JS to C++ callback wrappers to catch any Napi::Error exceptions
// and rethrow them as JavaScript exceptions before returning from the callback.
template <typename Callable>
inline napi_value WrapCallback(Callable callback) {
#ifdef NAPI_CPP_EXCEPTIONS
inline napi_value WrapCallback(napi_env env, Callable callback) {
#if defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
try {
return callback();
} catch (const Error& e) {
e.ThrowAsJavaScriptException();
return nullptr;
}
#else // NAPI_CPP_EXCEPTIONS
#ifdef NAPI_CPP_EXCEPTIONS_ALL
catch (const std::exception& e) {
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
return nullptr;
} catch (...) {
Napi::Error::New(env, "A native exception was thrown")
.ThrowAsJavaScriptException();
return nullptr;
}
#endif // NAPI_CPP_EXCEPTIONS_ALL
#else // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
// When C++ exceptions are disabled, errors are immediately thrown as JS
// exceptions, so there is no need to catch and rethrow them here.
return callback();
#endif // NAPI_CPP_EXCEPTIONS
#endif // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
}

// For use in JS to C++ void callback wrappers to catch any Napi::Error
// exceptions and rethrow them as JavaScript exceptions before returning from
// the callback.
template <typename Callable>
inline void WrapVoidCallback(Callable callback) {
#ifdef NAPI_CPP_EXCEPTIONS
inline void WrapVoidCallback(napi_env env, Callable callback) {
#if defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
try {
callback();
} catch (const Error& e) {
e.ThrowAsJavaScriptException();
}
#else // NAPI_CPP_EXCEPTIONS
#ifdef NAPI_CPP_EXCEPTIONS_ALL
catch (const std::exception& e) {
Napi::Error::New(env, e.what()).ThrowAsJavaScriptException();
} catch (...) {
Napi::Error::New(env, "A native exception was thrown")
.ThrowAsJavaScriptException();
}
#endif // NAPI_CPP_EXCEPTIONS_ALL
#else // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
// When C++ exceptions are disabled, errors are immediately thrown as JS
// exceptions, so there is no need to catch and rethrow them here.
callback();
#endif // NAPI_CPP_EXCEPTIONS
#endif // defined(NAPI_CPP_EXCEPTIONS) || defined(NAPI_CPP_EXCEPTIONS_ALL)
}

template <typename Callable, typename Return>
struct CallbackData {
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
CallbackData* callbackData =
static_cast<CallbackData*>(callbackInfo.Data());
Expand All @@ -130,7 +148,7 @@ struct CallbackData {
template <typename Callable>
struct CallbackData<Callable, void> {
static inline napi_value Wrapper(napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
CallbackData* callbackData =
static_cast<CallbackData*>(callbackInfo.Data());
Expand All @@ -147,7 +165,7 @@ struct CallbackData<Callable, void> {
template <void (*Callback)(const CallbackInfo& info)>
napi_value TemplatedVoidCallback(napi_env env,
napi_callback_info info) NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo cbInfo(env, info);
Callback(cbInfo);
return nullptr;
Expand All @@ -157,7 +175,7 @@ napi_value TemplatedVoidCallback(napi_env env,
template <Napi::Value (*Callback)(const CallbackInfo& info)>
napi_value TemplatedCallback(napi_env env,
napi_callback_info info) NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo cbInfo(env, info);
// MSVC requires to copy 'Callback' function pointer to a local variable
// before invoking it.
Expand All @@ -170,7 +188,7 @@ template <typename T,
Napi::Value (T::*UnwrapCallback)(const CallbackInfo& info)>
napi_value TemplatedInstanceCallback(napi_env env,
napi_callback_info info) NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo cbInfo(env, info);
T* instance = T::Unwrap(cbInfo.This().As<Object>());
return instance ? (instance->*UnwrapCallback)(cbInfo) : Napi::Value();
Expand All @@ -180,7 +198,7 @@ napi_value TemplatedInstanceCallback(napi_env env,
template <typename T, void (T::*UnwrapCallback)(const CallbackInfo& info)>
napi_value TemplatedInstanceVoidCallback(napi_env env, napi_callback_info info)
NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo cbInfo(env, info);
T* instance = T::Unwrap(cbInfo.This().As<Object>());
if (instance) (instance->*UnwrapCallback)(cbInfo);
Expand All @@ -198,7 +216,7 @@ struct FinalizeData {
static inline void Wrapper(node_api_nogc_env env,
void* data,
void* finalizeHint) NAPI_NOEXCEPT {
WrapVoidCallback([&] {
WrapVoidCallback(env, [&] {
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
finalizeData->callback(env, static_cast<T*>(data));
delete finalizeData;
Expand Down Expand Up @@ -228,7 +246,7 @@ struct FinalizeData {
static inline void WrapperWithHint(node_api_nogc_env env,
void* data,
void* finalizeHint) NAPI_NOEXCEPT {
WrapVoidCallback([&] {
WrapVoidCallback(env, [&] {
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
delete finalizeData;
Expand All @@ -253,7 +271,7 @@ struct FinalizeData {
static inline void WrapperGCWithoutData(napi_env env,
void* /*data*/,
void* finalizeHint) NAPI_NOEXCEPT {
WrapVoidCallback([&] {
WrapVoidCallback(env, [&] {
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
finalizeData->callback(env);
delete finalizeData;
Expand All @@ -263,7 +281,7 @@ struct FinalizeData {
static inline void WrapperGC(napi_env env,
void* data,
void* finalizeHint) NAPI_NOEXCEPT {
WrapVoidCallback([&] {
WrapVoidCallback(env, [&] {
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
finalizeData->callback(env, static_cast<T*>(data));
delete finalizeData;
Expand All @@ -273,7 +291,7 @@ struct FinalizeData {
static inline void WrapperGCWithHint(napi_env env,
void* data,
void* finalizeHint) NAPI_NOEXCEPT {
WrapVoidCallback([&] {
WrapVoidCallback(env, [&] {
FinalizeData* finalizeData = static_cast<FinalizeData*>(finalizeHint);
finalizeData->callback(env, static_cast<T*>(data), finalizeData->hint);
delete finalizeData;
Expand Down Expand Up @@ -340,7 +358,7 @@ struct ThreadSafeFinalize {
template <typename ContextType, typename DataType, typename CallJs, CallJs call>
inline typename std::enable_if<call != static_cast<CallJs>(nullptr)>::type
CallJsWrapper(napi_env env, napi_value jsCallback, void* context, void* data) {
details::WrapVoidCallback([&]() {
details::WrapVoidCallback(env, [&]() {
call(env,
Function(env, jsCallback),
static_cast<ContextType*>(context),
Expand All @@ -354,7 +372,7 @@ CallJsWrapper(napi_env env,
napi_value jsCallback,
void* /*context*/,
void* /*data*/) {
details::WrapVoidCallback([&]() {
details::WrapVoidCallback(env, [&]() {
if (jsCallback != nullptr) {
Function(env, jsCallback).Call(0, nullptr);
}
Expand Down Expand Up @@ -388,7 +406,7 @@ template <typename Getter, typename Setter>
struct AccessorCallbackData {
static inline napi_value GetterWrapper(napi_env env,
napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
AccessorCallbackData* callbackData =
static_cast<AccessorCallbackData*>(callbackInfo.Data());
Expand All @@ -399,7 +417,7 @@ struct AccessorCallbackData {

static inline napi_value SetterWrapper(napi_env env,
napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
AccessorCallbackData* callbackData =
static_cast<AccessorCallbackData*>(callbackInfo.Data());
Expand Down Expand Up @@ -490,7 +508,7 @@ class HasBasicFinalizer {
inline napi_value RegisterModule(napi_env env,
napi_value exports,
ModuleRegisterCallback registerCallback) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
return napi_value(
registerCallback(Napi::Env(env), Napi::Object(env, exports)));
});
Expand Down Expand Up @@ -4479,7 +4497,7 @@ inline ClassPropertyDescriptor<T> InstanceWrap<T>::InstanceValue(
template <typename T>
inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
InstanceVoidMethodCallbackData* callbackData =
reinterpret_cast<InstanceVoidMethodCallbackData*>(callbackInfo.Data());
Expand All @@ -4494,7 +4512,7 @@ inline napi_value InstanceWrap<T>::InstanceVoidMethodCallbackWrapper(
template <typename T>
inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
InstanceMethodCallbackData* callbackData =
reinterpret_cast<InstanceMethodCallbackData*>(callbackInfo.Data());
Expand All @@ -4508,7 +4526,7 @@ inline napi_value InstanceWrap<T>::InstanceMethodCallbackWrapper(
template <typename T>
inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
InstanceAccessorCallbackData* callbackData =
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
Expand All @@ -4522,7 +4540,7 @@ inline napi_value InstanceWrap<T>::InstanceGetterCallbackWrapper(
template <typename T>
inline napi_value InstanceWrap<T>::InstanceSetterCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
InstanceAccessorCallbackData* callbackData =
reinterpret_cast<InstanceAccessorCallbackData*>(callbackInfo.Data());
Expand All @@ -4538,7 +4556,7 @@ template <typename T>
template <typename InstanceWrap<T>::InstanceSetterCallback method>
inline napi_value InstanceWrap<T>::WrappedMethod(
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
const CallbackInfo cbInfo(env, info);
T* instance = T::Unwrap(cbInfo.This().As<Object>());
if (instance) (instance->*method)(cbInfo, cbInfo[0]);
Expand Down Expand Up @@ -4933,10 +4951,10 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
bool isConstructCall = (new_target != nullptr);
if (!isConstructCall) {
return details::WrapCallback(
[&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
env, [&] { return T::OnCalledAsFunction(CallbackInfo(env, info)); });
}

napi_value wrapper = details::WrapCallback([&] {
napi_value wrapper = details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
T* instance = new T(callbackInfo);
#ifdef NAPI_CPP_EXCEPTIONS
Expand All @@ -4960,7 +4978,7 @@ inline napi_value ObjectWrap<T>::ConstructorCallbackWrapper(
template <typename T>
inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
StaticVoidMethodCallbackData* callbackData =
reinterpret_cast<StaticVoidMethodCallbackData*>(callbackInfo.Data());
Expand All @@ -4973,7 +4991,7 @@ inline napi_value ObjectWrap<T>::StaticVoidMethodCallbackWrapper(
template <typename T>
inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
StaticMethodCallbackData* callbackData =
reinterpret_cast<StaticMethodCallbackData*>(callbackInfo.Data());
Expand All @@ -4985,7 +5003,7 @@ inline napi_value ObjectWrap<T>::StaticMethodCallbackWrapper(
template <typename T>
inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
StaticAccessorCallbackData* callbackData =
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
Expand All @@ -4997,7 +5015,7 @@ inline napi_value ObjectWrap<T>::StaticGetterCallbackWrapper(
template <typename T>
inline napi_value ObjectWrap<T>::StaticSetterCallbackWrapper(
napi_env env, napi_callback_info info) {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
CallbackInfo callbackInfo(env, info);
StaticAccessorCallbackData* callbackData =
reinterpret_cast<StaticAccessorCallbackData*>(callbackInfo.Data());
Expand Down Expand Up @@ -5066,7 +5084,7 @@ template <typename T>
template <typename ObjectWrap<T>::StaticSetterCallback method>
inline napi_value ObjectWrap<T>::WrappedMethod(
napi_env env, napi_callback_info info) NAPI_NOEXCEPT {
return details::WrapCallback([&] {
return details::WrapCallback(env, [&] {
const CallbackInfo cbInfo(env, info);
// MSVC requires to copy 'method' function pointer to a local variable
// before invoking it.
Expand Down Expand Up @@ -5384,10 +5402,10 @@ inline void AsyncWorker::OnAsyncWorkComplete(napi_env env,
AsyncWorker* self = static_cast<AsyncWorker*>(asyncworker);
self->OnWorkComplete(env, status);
}
inline void AsyncWorker::OnWorkComplete(Napi::Env /*env*/, napi_status status) {
inline void AsyncWorker::OnWorkComplete(Napi::Env env, napi_status status) {
if (status != napi_cancelled) {
HandleScope scope(_env);
details::WrapCallback([&] {
details::WrapCallback(env, [&] {
if (_error.size() == 0) {
OnOK();
} else {
Expand Down Expand Up @@ -6299,7 +6317,7 @@ inline void ThreadSafeFunction::CallJS(napi_env env,
return;
}

details::WrapVoidCallback([&]() {
details::WrapVoidCallback(env, [&]() {
if (data != nullptr) {
auto* callbackWrapper = static_cast<CallbackWrapper*>(data);
(*callbackWrapper)(env, Function(env, jsCallback));
Expand Down

0 comments on commit fc130ef

Please sign in to comment.