| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 16ee02f commit ea73702
10 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -103,6 +103,8 @@ function hrtimeBigInt() { | |||
| 103 | 103 | return hrBigintValues[0]; | |
| 104 | 104 | } | |
| 105 | 105 | ||
| 106 | + function nop() {} | ||
| 107 | + | ||
| 106 | 108 | // The execution of this function itself should not cause any side effects. | |
| 107 | 109 | function wrapProcessMethods(binding) { | |
| 108 | 110 | const { | |
@@ -193,6 +195,16 @@ function wrapProcessMethods(binding) { | |||
| 193 | 195 | // in the user land. Either document it, or deprecate it in favor of a | |
| 194 | 196 | // better public alternative. | |
| 195 | 197 | process.reallyExit(process.exitCode || 0); | |
| 198 | + | ||
| 199 | + // If this is a worker, v8::Isolate::TerminateExecution() is called above. | ||
| 200 | + // That function spoofs the stack pointer to cause the stack guard | ||
| 201 | + // check to throw the termination exception. Because v8 performs | ||
| 202 | + // stack guard check upon every function call, we give it a chance. | ||
| 203 | + // | ||
| 204 | + // Without this, user code after `process.exit()` would take effect. | ||
| 205 | + // test/parallel/test-worker-voluntarily-exit-followed-by-addition.js | ||
| 206 | + // test/parallel/test-worker-voluntarily-exit-followed-by-throw.js | ||
| 207 | + nop(); | ||
| 196 | 208 | } | |
| 197 | 209 | ||
| 198 | 210 | function kill(pid, sig) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -314,6 +314,9 @@ class CallbackWrapperBase : public CallbackWrapper { | |||
| 314 | 314 | env->CallIntoModule([&](napi_env env) { result = cb(env, cbinfo_wrapper); }, | |
| 315 | 315 | [&](napi_env env, v8::Local<v8::Value> value) { | |
| 316 | 316 | exceptionOccurred = true; | |
| 317 | + if (env->terminatedOrTerminating()) { | ||
| 318 | + return; | ||
| 319 | + } | ||
| 317 | 320 | env->isolate->ThrowException(value); | |
| 318 | 321 | }); | |
| 319 | 322 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -72,9 +72,20 @@ struct napi_env__ { | |||
| 72 | 72 | } | |
| 73 | 73 | ||
| 74 | 74 | static inline void HandleThrow(napi_env env, v8::Local<v8::Value> value) { | |
| 75 | + if (env->terminatedOrTerminating()) { | ||
| 76 | + return; | ||
| 77 | + } | ||
| 75 | 78 | env->isolate->ThrowException(value); | |
| 76 | 79 | } | |
| 77 | 80 | ||
| 81 | + // i.e. whether v8 exited or is about to exit | ||
| 82 | + inline bool terminatedOrTerminating() { | ||
| 83 | + return this->isolate->IsExecutionTerminating() || !can_call_into_js(); | ||
| 84 | + } | ||
| 85 | + | ||
| 86 | + // v8 uses a special exception to indicate termination, the | ||
| 87 | + // `handle_exception` callback should identify such case using | ||
| 88 | + // terminatedOrTerminating() before actually handle the exception | ||
| 78 | 89 | template <typename T, typename U = decltype(HandleThrow)> | |
| 79 | 90 | inline void CallIntoModule(T&& call, U&& handle_exception = HandleThrow) { | |
| 80 | 91 | int open_handle_scopes_before = open_handle_scopes; | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -95,6 +95,9 @@ template <bool enforceUncaughtExceptionPolicy, typename T> | |||
| 95 | 95 | void node_napi_env__::CallbackIntoModule(T&& call) { | |
| 96 | 96 | CallIntoModule(call, [](napi_env env_, v8::Local<v8::Value> local_err) { | |
| 97 | 97 | node_napi_env__* env = static_cast<node_napi_env__*>(env_); | |
| 98 | + if (env->terminatedOrTerminating()) { | ||
| 99 | + return; | ||
| 100 | + } | ||
| 98 | 101 | node::Environment* node_env = env->node_env(); | |
| 99 | 102 | if (!node_env->options()->force_node_api_uncaught_exceptions_policy && | |
| 100 | 103 | !enforceUncaughtExceptionPolicy) { | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -553,7 +553,9 @@ TEST_F(EnvironmentTest, ExitHandlerTest) { | |||
| 553 | 553 | callback_calls++; | |
| 554 | 554 | node::Stop(*env); | |
| 555 | 555 | }); | |
| 556 | - node::LoadEnvironment(*env, "process.exit(42)").ToLocalChecked(); | ||
| 556 | + // When terminating, v8 throws makes the current embedder call bail out | ||
| 557 | + // with MaybeLocal<>() | ||
| 558 | + EXPECT_TRUE(node::LoadEnvironment(*env, "process.exit(42)").IsEmpty()); | ||
| 557 | 559 | EXPECT_EQ(callback_calls, 1); | |
| 558 | 560 | } | |
| 559 | 561 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -19,8 +19,8 @@ if (isMainThread) { | |||
| 19 | 19 | const { Test } = require(`./build/${common.buildType}/test_worker_terminate`); | |
| 20 | 20 | ||
| 21 | 21 | const { counter } = workerData; | |
| 22 | - // Test() tries to call a function twice and asserts that the second call does | ||
| 23 | - // not work because of a pending exception. | ||
| 22 | + // Test() tries to call a function and asserts it fails because of a | ||
| 23 | + // pending termination exception. | ||
| 24 | 24 | Test(() => { | |
| 25 | 25 | Atomics.add(counter, 0, 1); | |
| 26 | 26 | process.exit(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -17,8 +17,6 @@ napi_value Test(napi_env env, napi_callback_info info) { | |||
| 17 | 17 | NODE_API_ASSERT(env, t == napi_function, | |
| 18 | 18 | "Wrong first argument, function expected."); | |
| 19 | 19 | ||
| 20 | - status = napi_call_function(env, recv, argv[0], 0, NULL, NULL); | ||
| 21 | - assert(status == napi_ok); | ||
| 22 | 20 | status = napi_call_function(env, recv, argv[0], 0, NULL, NULL); | |
| 23 | 21 | assert(status == napi_pending_exception); | |
| 24 | 22 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -12,6 +12,7 @@ const { Worker } = require('worker_threads'); | |||
| 12 | 12 | const workerData = new Int32Array(new SharedArrayBuffer(4)); | |
| 13 | 13 | const w = new Worker(` | |
| 14 | 14 | const { createHook } = require('async_hooks'); | |
| 15 | + const { workerData } = require('worker_threads'); | ||
| 15 | 16 | ||
| 16 | 17 | setImmediate(async () => { | |
| 17 | 18 | createHook({ init() {} }).enable(); | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,18 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const { Worker, isMainThread } = require('worker_threads'); | ||
| 5 | + | ||
| 6 | + if (isMainThread) { | ||
| 7 | + const workerData = new Int32Array(new SharedArrayBuffer(4)); | ||
| 8 | + new Worker(__filename, { | ||
| 9 | + workerData, | ||
| 10 | + }); | ||
| 11 | + process.on('beforeExit', common.mustCall(() => { | ||
| 12 | + assert.strictEqual(workerData[0], 0); | ||
| 13 | + })); | ||
| 14 | + } else { | ||
| 15 | + const { workerData } = require('worker_threads'); | ||
| 16 | + process.exit(); | ||
| 17 | + workerData[0] = 1; | ||
| 18 | + } | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,23 @@ | |||
| 1 | + 'use strict'; | ||
| 2 | + const common = require('../common'); | ||
| 3 | + const assert = require('assert'); | ||
| 4 | + const { Worker, isMainThread } = require('worker_threads'); | ||
| 5 | + | ||
| 6 | + if (isMainThread) { | ||
| 7 | + const workerData = new Int32Array(new SharedArrayBuffer(4)); | ||
| 8 | + new Worker(__filename, { | ||
| 9 | + workerData, | ||
| 10 | + }); | ||
| 11 | + process.on('beforeExit', common.mustCall(() => { | ||
| 12 | + assert.strictEqual(workerData[0], 0); | ||
| 13 | + })); | ||
| 14 | + } else { | ||
| 15 | + const { workerData } = require('worker_threads'); | ||
| 16 | + try { | ||
| 17 | + process.exit(); | ||
| 18 | + throw new Error('xxx'); | ||
| 19 | + // eslint-disable-next-line no-unused-vars | ||
| 20 | + } catch (err) { | ||
| 21 | + workerData[0] = 1; | ||
| 22 | + } | ||
| 23 | + } | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments