From cd8277ac6011ec9c047287dd1a1f3fa665c51866 Mon Sep 17 00:00:00 2001 From: toyobayashi Date: Mon, 28 Jun 2021 18:52:12 +0800 Subject: [PATCH] add `Napi::Error::Fatal` --- include/napi-inl.h | 33 ++++++++++++++++++++++++++++++++- include/napi.h | 14 ++++++++++---- include/node_api.h | 1 + package.json | 2 +- 4 files changed, 44 insertions(+), 6 deletions(-) diff --git a/include/napi-inl.h b/include/napi-inl.h index 28b9f4b2..319ec747 100644 --- a/include/napi-inl.h +++ b/include/napi-inl.h @@ -2172,6 +2172,11 @@ inline Error Error::New(napi_env env, const std::string& message) { return Error::New(env, message.c_str(), message.size(), napi_create_error); } +inline NAPI_NO_RETURN void Error::Fatal(const char* location, const char* message) { + // napi_fatal_error(location, NAPI_AUTO_LENGTH, message, NAPI_AUTO_LENGTH); + abort(); +} + inline Error::Error() : ObjectReference() { } @@ -2231,12 +2236,38 @@ inline const std::string& Error::Message() const NAPI_NOEXCEPT { inline void Error::ThrowAsJavaScriptException() const { HandleScope scope(_env); if (!IsEmpty()) { - +#ifdef NODE_API_SWALLOW_UNTHROWABLE_EXCEPTIONS + bool pendingException = false; + + // check if there is already a pending exception. If so don't try to throw a + // new one as that is not allowed/possible + napi_status status = napi_is_exception_pending(_env, &pendingException); + + if ((status != napi_ok) || + ((status == napi_ok) && (pendingException == false))) { + // We intentionally don't use `NAPI_THROW_*` macros here to ensure + // that there is no possible recursion as `ThrowAsJavaScriptException` + // is part of `NAPI_THROW_*` macro definition for noexcept. + + status = napi_throw(_env, Value()); + + if (status == napi_pending_exception) { + // The environment must be terminating as we checked earlier and there + // was no pending exception. In this case continuing will result + // in a fatal error and there is nothing the author has done incorrectly + // in their code that is worth flagging through a fatal error + return; + } + } else { + status = napi_pending_exception; + } +#else // We intentionally don't use `NAPI_THROW_*` macros here to ensure // that there is no possible recursion as `ThrowAsJavaScriptException` // is part of `NAPI_THROW_*` macro definition for noexcept. napi_status status = napi_throw(_env, Value()); +#endif #ifdef NAPI_CPP_EXCEPTIONS if (status != napi_ok) { diff --git a/include/napi.h b/include/napi.h index eb550e8d..d18fb09b 100644 --- a/include/napi.h +++ b/include/napi.h @@ -98,7 +98,12 @@ static_assert(sizeof(char16_t) == sizeof(wchar_t), "Size mismatch between char16 NAPI_DISALLOW_ASSIGN(CLASS) \ NAPI_DISALLOW_COPY(CLASS) -#define NAPI_FATAL_IF_FAILED(status, location, message) +#define NAPI_FATAL_IF_FAILED(status, location, message) \ + do { \ + if ((status) != napi_ok) { \ + Napi::Error::Fatal((location), (message)); \ + } \ + } while (0) //////////////////////////////////////////////////////////////////////////////// /// Node-API C++ Wrapper Classes @@ -1372,6 +1377,8 @@ namespace Napi { static Error New(napi_env env, const char* message); static Error New(napi_env env, const std::string& message); + static NAPI_NO_RETURN void Fatal(const char* location, const char* message); + Error(); Error(napi_env env, napi_value value); @@ -2303,9 +2310,8 @@ namespace Napi { Finalizer finalizeCallback, FinalizerDataType* data = nullptr); - TypedThreadSafeFunction(); - TypedThreadSafeFunction( - napi_threadsafe_function tsFunctionValue); + TypedThreadSafeFunction(); + TypedThreadSafeFunction(napi_threadsafe_function tsFunctionValue); operator napi_threadsafe_function() const; diff --git a/include/node_api.h b/include/node_api.h index 6911a1f7..55866f18 100644 --- a/include/node_api.h +++ b/include/node_api.h @@ -4,6 +4,7 @@ #include "js_native_api.h" #define NAPI_MODULE_EXPORT __attribute__((used)) +#define NAPI_NO_RETURN __attribute__((__noreturn__)) typedef napi_value (*napi_addon_register_func)(napi_env env, napi_value exports); diff --git a/package.json b/package.json index 7065774f..d9b653e6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@tybys/emnapi", - "version": "0.3.0", + "version": "0.3.1", "description": "Node-API implementation for Emscripten", "main": "index.js", "typings": "index.d.ts",