mirror of
https://github.com/zebrajr/node.git
synced 2026-01-15 12:15:26 +00:00
n-api: add napi_fatal_exception
Add function to trigger and uncaught exception. Useful if an async callback throws an exception with no way to recover. Backport-PR-URL: https://github.com/nodejs/node/pull/19447 PR-URL: https://github.com/nodejs/node/pull/19337 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
committed by
Myles Borins
parent
eb29266878
commit
49cd4fad89
@@ -539,6 +539,20 @@ This API returns true if an exception is pending.
|
||||
|
||||
This API can be called even if there is a pending JavaScript exception.
|
||||
|
||||
#### napi_fatal_exception
|
||||
<!-- YAML
|
||||
added: REPLACEME
|
||||
-->
|
||||
```C
|
||||
napi_status napi_fatal_exception(napi_env env, napi_value err);
|
||||
```
|
||||
|
||||
- `[in] env`: The environment that the API is invoked under.
|
||||
- `[in] err`: The error you want to pass to `uncaughtException`.
|
||||
|
||||
Trigger an `uncaughtException` in JavaScript. Useful if an async
|
||||
callback throws an exception with no way to recover.
|
||||
|
||||
### Fatal Errors
|
||||
|
||||
In the event of an unrecoverable error in a native module, a fatal error can be
|
||||
|
||||
@@ -293,6 +293,13 @@ v8::Local<v8::Value> V8LocalValueFromJsValue(napi_value v) {
|
||||
return local;
|
||||
}
|
||||
|
||||
static inline void trigger_fatal_exception(
|
||||
napi_env env, v8::Local<v8::Value> local_err) {
|
||||
v8::Local<v8::Message> local_msg =
|
||||
v8::Exception::CreateMessage(env->isolate, local_err);
|
||||
node::FatalException(env->isolate, local_err, local_msg);
|
||||
}
|
||||
|
||||
static inline napi_status V8NameFromPropertyDescriptor(napi_env env,
|
||||
const napi_property_descriptor* p,
|
||||
v8::Local<v8::Name>* result) {
|
||||
@@ -967,6 +974,16 @@ napi_status napi_get_last_error_info(napi_env env,
|
||||
return napi_ok;
|
||||
}
|
||||
|
||||
napi_status napi_fatal_exception(napi_env env, napi_value err) {
|
||||
NAPI_PREAMBLE(env);
|
||||
CHECK_ARG(env, err);
|
||||
|
||||
v8::Local<v8::Value> local_err = v8impl::V8LocalValueFromJsValue(err);
|
||||
v8impl::trigger_fatal_exception(env, local_err);
|
||||
|
||||
return napi_clear_last_error(env);
|
||||
}
|
||||
|
||||
NAPI_NO_RETURN void napi_fatal_error(const char* location,
|
||||
size_t location_len,
|
||||
const char* message,
|
||||
@@ -3457,10 +3474,9 @@ class Work : public node::AsyncResource {
|
||||
// report it as a fatal exception. (There is no JavaScript on the
|
||||
// callstack that can possibly handle it.)
|
||||
if (!env->last_exception.IsEmpty()) {
|
||||
v8::TryCatch try_catch(env->isolate);
|
||||
env->isolate->ThrowException(
|
||||
v8::Local<v8::Value>::New(env->isolate, env->last_exception));
|
||||
node::FatalException(env->isolate, try_catch);
|
||||
v8::Local<v8::Value> local_err = v8::Local<v8::Value>::New(
|
||||
env->isolate, env->last_exception);
|
||||
v8impl::trigger_fatal_exception(env, local_err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -103,6 +103,8 @@ NAPI_EXTERN napi_status
|
||||
napi_get_last_error_info(napi_env env,
|
||||
const napi_extended_error_info** result);
|
||||
|
||||
NAPI_EXTERN napi_status napi_fatal_exception(napi_env env, napi_value err);
|
||||
|
||||
NAPI_EXTERN NAPI_NO_RETURN void napi_fatal_error(const char* location,
|
||||
size_t location_len,
|
||||
const char* message,
|
||||
|
||||
@@ -118,6 +118,11 @@ void GetSockOrPeerName(const v8::FunctionCallbackInfo<v8::Value>& args) {
|
||||
args.GetReturnValue().Set(err);
|
||||
}
|
||||
|
||||
void FatalException(v8::Isolate* isolate,
|
||||
v8::Local<v8::Value> error,
|
||||
v8::Local<v8::Message> message);
|
||||
|
||||
|
||||
void SignalExit(int signo);
|
||||
#ifdef __POSIX__
|
||||
void RegisterSignalHandler(int signal,
|
||||
|
||||
18
test/addons-napi/test_async/test-uncaught.js
Normal file
18
test/addons-napi/test_async/test-uncaught.js
Normal file
@@ -0,0 +1,18 @@
|
||||
'use strict';
|
||||
const common = require('../../common');
|
||||
const assert = require('assert');
|
||||
const test_async = require(`./build/${common.buildType}/test_async`);
|
||||
|
||||
process.on('uncaughtException', common.mustCall(function(err) {
|
||||
try {
|
||||
throw new Error('should not fail');
|
||||
} catch (err) {
|
||||
assert.strictEqual(err.message, 'should not fail');
|
||||
}
|
||||
assert.strictEqual(err.message, 'uncaught');
|
||||
}));
|
||||
|
||||
// Successful async execution and completion callback.
|
||||
test_async.Test(5, {}, common.mustCall(function() {
|
||||
throw new Error('uncaught');
|
||||
}));
|
||||
8
test/addons-napi/test_fatal_exception/binding.gyp
Normal file
8
test/addons-napi/test_fatal_exception/binding.gyp
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"targets": [
|
||||
{
|
||||
"target_name": "test_fatal_exception",
|
||||
"sources": [ "test_fatal_exception.c" ]
|
||||
}
|
||||
]
|
||||
}
|
||||
11
test/addons-napi/test_fatal_exception/test.js
Normal file
11
test/addons-napi/test_fatal_exception/test.js
Normal file
@@ -0,0 +1,11 @@
|
||||
'use strict';
|
||||
const common = require('../../common');
|
||||
const assert = require('assert');
|
||||
const test_fatal = require(`./build/${common.buildType}/test_fatal_exception`);
|
||||
|
||||
process.on('uncaughtException', common.mustCall(function(err) {
|
||||
assert.strictEqual(err.message, 'fatal error');
|
||||
}));
|
||||
|
||||
const err = new Error('fatal error');
|
||||
test_fatal.Test(err);
|
||||
26
test/addons-napi/test_fatal_exception/test_fatal_exception.c
Normal file
26
test/addons-napi/test_fatal_exception/test_fatal_exception.c
Normal file
@@ -0,0 +1,26 @@
|
||||
#include <node_api.h>
|
||||
#include "../common.h"
|
||||
|
||||
napi_value Test(napi_env env, napi_callback_info info) {
|
||||
napi_value err;
|
||||
size_t argc = 1;
|
||||
|
||||
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &err, NULL, NULL));
|
||||
|
||||
NAPI_CALL(env, napi_fatal_exception(env, err));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
napi_value Init(napi_env env, napi_value exports) {
|
||||
napi_property_descriptor properties[] = {
|
||||
DECLARE_NAPI_PROPERTY("Test", Test),
|
||||
};
|
||||
|
||||
NAPI_CALL(env, napi_define_properties(
|
||||
env, exports, sizeof(properties) / sizeof(*properties), properties));
|
||||
|
||||
return exports;
|
||||
}
|
||||
|
||||
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)
|
||||
Reference in New Issue
Block a user