From b9529078b4d73733931a734b5753d22ee1d3fe77 Mon Sep 17 00:00:00 2001 From: isurusiri Date: Wed, 25 Apr 2018 07:11:26 +0530 Subject: [PATCH 01/76] doc: modified docs to reflect how to invoke gc on Wrapping C++ objects Currently the documentation for Wrapping C++ Objects doesn't explain how to destruct an object by explicitly invoking the garbage collector. This commit includes a modification to docs which explains how to invoke garbage collector to delete an object by executing its destructor. Fixes: https://github.com/nodejs/node/issues/19876 --- doc/api/addons.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 3c4c7b39bedfeb..cf4b0968eecdba 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -595,6 +595,8 @@ class MyObject : public node::ObjectWrap { static void PlusOne(const v8::FunctionCallbackInfo& args); static v8::Persistent constructor; double value_; + napi_env env_; + napi_ref wrapper_; }; } // namespace demo @@ -609,6 +611,8 @@ prototype: ```cpp // myobject.cc #include "myobject.h" +#include +using std::cout; namespace demo { @@ -630,6 +634,9 @@ MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { + cout << "Deleting object \n"; + napi_delete_reference(env_, wrapper_); + cout << "Deleted object \n"; } void MyObject::Init(Local exports) { @@ -704,14 +711,20 @@ Test it with: // test.js const addon = require('./build/Release/addon'); -const obj = new addon.MyObject(10); +let obj = new addon.MyObject(10); console.log(obj.plusOne()); // Prints: 11 console.log(obj.plusOne()); // Prints: 12 console.log(obj.plusOne()); // Prints: 13 + +obj = null; +global.gc(); +// Prints: Deleting object ``` +Note that, in this example, the garbage collector is executed explicitly to +properly invoke the wrapper objects' destructor. ### Factory of wrapped objects From 51491dd1e77a66d8dd0c0f1097801f941eef9bd9 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 23 Apr 2018 12:39:14 +0200 Subject: [PATCH 02/76] test: remove crypto.DEFAULT_ENCODING usage This commit removes the usage of the deprectated crypto.DEFAULT_ENCODING. PR-URL: https://github.com/nodejs/node/pull/20221 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- test/parallel/test-crypto-binary-default.js | 4 +++- test/parallel/test-crypto-certificate.js | 2 -- test/parallel/test-crypto-ecb.js | 2 -- test/parallel/test-crypto-padding-aes256.js | 2 -- test/parallel/test-crypto-padding.js | 2 -- test/parallel/test-crypto-random.js | 2 -- test/parallel/test-crypto-verify-failure.js | 2 -- test/parallel/test-crypto.js | 2 -- 8 files changed, 3 insertions(+), 15 deletions(-) diff --git a/test/parallel/test-crypto-binary-default.js b/test/parallel/test-crypto-binary-default.js index 6cdc894753c3ac..228e2cc8abdc81 100644 --- a/test/parallel/test-crypto-binary-default.js +++ b/test/parallel/test-crypto-binary-default.js @@ -20,6 +20,8 @@ // USE OR OTHER DEALINGS IN THE SOFTWARE. 'use strict'; +// Flags: --expose-internals + // This is the same as test/simple/test-crypto, but from before the shift // to use buffers by default. @@ -36,7 +38,7 @@ const tls = require('tls'); const fixtures = require('../common/fixtures'); const DH_NOT_SUITABLE_GENERATOR = crypto.constants.DH_NOT_SUITABLE_GENERATOR; -crypto.DEFAULT_ENCODING = 'latin1'; +require('internal/crypto/util').setDefaultEncoding('latin1'); // Test Certificates const certPem = fixtures.readSync('test_cert.pem', 'ascii'); diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js index f94c82474e95aa..acbfdf66cc78c4 100644 --- a/test/parallel/test-crypto-certificate.js +++ b/test/parallel/test-crypto-certificate.js @@ -29,8 +29,6 @@ const crypto = require('crypto'); const { Certificate } = crypto; const fixtures = require('../common/fixtures'); -crypto.DEFAULT_ENCODING = 'buffer'; - // Test Certificates const spkacValid = fixtures.readSync('spkac.valid'); const spkacFail = fixtures.readSync('spkac.fail'); diff --git a/test/parallel/test-crypto-ecb.js b/test/parallel/test-crypto-ecb.js index 4faf4af2c576fd..c88ebaabb05e7f 100644 --- a/test/parallel/test-crypto-ecb.js +++ b/test/parallel/test-crypto-ecb.js @@ -30,8 +30,6 @@ if (common.hasFipsCrypto) const assert = require('assert'); const crypto = require('crypto'); -crypto.DEFAULT_ENCODING = 'buffer'; - // Testing whether EVP_CipherInit_ex is functioning correctly. // Reference: bug#1997 diff --git a/test/parallel/test-crypto-padding-aes256.js b/test/parallel/test-crypto-padding-aes256.js index ea31c7e894ee53..d6c395f0a42d35 100644 --- a/test/parallel/test-crypto-padding-aes256.js +++ b/test/parallel/test-crypto-padding-aes256.js @@ -27,8 +27,6 @@ if (!common.hasCrypto) const assert = require('assert'); const crypto = require('crypto'); -crypto.DEFAULT_ENCODING = 'buffer'; - const iv = Buffer.from('00000000000000000000000000000000', 'hex'); const key = Buffer.from('0123456789abcdef0123456789abcdef' + '0123456789abcdef0123456789abcdef', 'hex'); diff --git a/test/parallel/test-crypto-padding.js b/test/parallel/test-crypto-padding.js index 00b600efb735e8..d4a5b95cec9242 100644 --- a/test/parallel/test-crypto-padding.js +++ b/test/parallel/test-crypto-padding.js @@ -27,8 +27,6 @@ if (!common.hasCrypto) const assert = require('assert'); const crypto = require('crypto'); -crypto.DEFAULT_ENCODING = 'buffer'; - // Input data. const ODD_LENGTH_PLAIN = 'Hello node world!'; const EVEN_LENGTH_PLAIN = 'Hello node world!AbC09876dDeFgHi'; diff --git a/test/parallel/test-crypto-random.js b/test/parallel/test-crypto-random.js index 77801f6d53eef2..f00e474b6f2798 100644 --- a/test/parallel/test-crypto-random.js +++ b/test/parallel/test-crypto-random.js @@ -32,8 +32,6 @@ const { kMaxLength } = require('buffer'); const kMaxUint32 = Math.pow(2, 32) - 1; const kMaxPossibleLength = Math.min(kMaxLength, kMaxUint32); -crypto.DEFAULT_ENCODING = 'buffer'; - // bump, we register a lot of exit listeners process.setMaxListeners(256); diff --git a/test/parallel/test-crypto-verify-failure.js b/test/parallel/test-crypto-verify-failure.js index 72dfb926413d8b..7e9fda9f6791f6 100644 --- a/test/parallel/test-crypto-verify-failure.js +++ b/test/parallel/test-crypto-verify-failure.js @@ -29,8 +29,6 @@ const crypto = require('crypto'); const tls = require('tls'); const fixtures = require('../common/fixtures'); -crypto.DEFAULT_ENCODING = 'buffer'; - const certPem = fixtures.readSync('test_cert.pem', 'ascii'); const options = { diff --git a/test/parallel/test-crypto.js b/test/parallel/test-crypto.js index 3047d37c962cff..9a93e8422fd0b4 100644 --- a/test/parallel/test-crypto.js +++ b/test/parallel/test-crypto.js @@ -30,8 +30,6 @@ const crypto = require('crypto'); const tls = require('tls'); const fixtures = require('../common/fixtures'); -crypto.DEFAULT_ENCODING = 'buffer'; - // Test Certificates const caPem = fixtures.readSync('test_ca.pem', 'ascii'); const certPem = fixtures.readSync('test_cert.pem', 'ascii'); From 293ff075f66dfb23c3d8a19ef5526024e90b350c Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 23 Apr 2018 14:54:23 +0200 Subject: [PATCH 03/76] test: add checkMethods function for Certificate This commit adds a checkMethods function so that it can be reused to avoid duplicating the same code for instance methods, and static methods of the Certificate object. PR-URL: https://github.com/nodejs/node/pull/20224 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- test/parallel/test-crypto-certificate.js | 24 +++++++----------------- 1 file changed, 7 insertions(+), 17 deletions(-) diff --git a/test/parallel/test-crypto-certificate.js b/test/parallel/test-crypto-certificate.js index acbfdf66cc78c4..a426e0be003da0 100644 --- a/test/parallel/test-crypto-certificate.js +++ b/test/parallel/test-crypto-certificate.js @@ -34,9 +34,7 @@ const spkacValid = fixtures.readSync('spkac.valid'); const spkacFail = fixtures.readSync('spkac.fail'); const spkacPem = fixtures.readSync('spkac.pem'); -{ - // Test instance methods - const certificate = new Certificate(); +function checkMethods(certificate) { assert.strictEqual(certificate.verifySpkac(spkacValid), true); assert.strictEqual(certificate.verifySpkac(spkacFail), false); @@ -55,21 +53,13 @@ const spkacPem = fixtures.readSync('spkac.pem'); } { - // Test static methods - assert.strictEqual(Certificate.verifySpkac(spkacValid), true); - assert.strictEqual(Certificate.verifySpkac(spkacFail), false); - - assert.strictEqual( - stripLineEndings(Certificate.exportPublicKey(spkacValid).toString('utf8')), - stripLineEndings(spkacPem.toString('utf8')) - ); - assert.strictEqual(Certificate.exportPublicKey(spkacFail), ''); + // Test instance methods + checkMethods(new Certificate()); +} - assert.strictEqual( - Certificate.exportChallenge(spkacValid).toString('utf8'), - 'fb9ab814-6677-42a4-a60c-f905d1a6924d' - ); - assert.strictEqual(Certificate.exportChallenge(spkacFail), ''); +{ + // Test static methods + checkMethods(Certificate); } function stripLineEndings(obj) { From 5e521a2f8f58ffd847d3a6f683f274c74e5b4ec1 Mon Sep 17 00:00:00 2001 From: Ulan Degenbaev Date: Thu, 12 Apr 2018 22:01:11 +0200 Subject: [PATCH 04/76] src: limit foreground tasks draining loop Foreground tasks that repost themselves can force the draining loop to run indefinitely long without giving other tasks chance to run. This limits the foreground task draining loop to run only the tasks that were in the tasks queue at the beginning of the loop. PR-URL: https://github.com/nodejs/node/pull/19987 Fixes: https://github.com/nodejs/node/issues/19937 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Yang Guo Reviewed-By: Colin Ihrig Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ben Noordhuis Reviewed-By: Anatoli Papirovski Reviewed-By: Khaidi Chu --- node.gyp | 1 + src/inspector_agent.cc | 2 +- src/node_platform.cc | 22 ++++++++++++--- src/node_platform.h | 10 +++++-- test/cctest/test_platform.cc | 55 ++++++++++++++++++++++++++++++++++++ 5 files changed, 83 insertions(+), 7 deletions(-) create mode 100644 test/cctest/test_platform.cc diff --git a/node.gyp b/node.gyp index 8347beb18245ca..abed8ad4c48c10 100644 --- a/node.gyp +++ b/node.gyp @@ -961,6 +961,7 @@ 'test/cctest/test_base64.cc', 'test/cctest/test_node_postmortem_metadata.cc', 'test/cctest/test_environment.cc', + 'test/cctest/test_platform.cc', 'test/cctest/test_util.cc', 'test/cctest/test_url.cc' ], diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index e143d316d2e6fa..fffaecdef3ddfa 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -316,7 +316,7 @@ class NodeInspectorClient : public V8InspectorClient { terminated_ = false; running_nested_loop_ = true; while (!terminated_ && channel_->waitForFrontendMessage()) { - platform_->FlushForegroundTasks(env_->isolate()); + while (platform_->FlushForegroundTasks(env_->isolate())) {} } terminated_ = false; running_nested_loop_ = false; diff --git a/src/node_platform.cc b/src/node_platform.cc index d96db086925c01..b8f1344727cfd6 100644 --- a/src/node_platform.cc +++ b/src/node_platform.cc @@ -95,7 +95,7 @@ void PerIsolatePlatformData::PostDelayedTask( } PerIsolatePlatformData::~PerIsolatePlatformData() { - FlushForegroundTasksInternal(); + while (FlushForegroundTasksInternal()) {} CancelPendingDelayedTasks(); uv_close(reinterpret_cast(flush_tasks_), @@ -223,7 +223,13 @@ bool PerIsolatePlatformData::FlushForegroundTasksInternal() { }); }); } - while (std::unique_ptr task = foreground_tasks_.Pop()) { + // Move all foreground tasks into a separate queue and flush that queue. + // This way tasks that are posted while flushing the queue will be run on the + // next call of FlushForegroundTasksInternal. + std::queue> tasks = foreground_tasks_.PopAll(); + while (!tasks.empty()) { + std::unique_ptr task = std::move(tasks.front()); + tasks.pop(); did_work = true; RunForegroundTask(std::move(task)); } @@ -254,8 +260,8 @@ void NodePlatform::CallDelayedOnForegroundThread(Isolate* isolate, std::unique_ptr(task), delay_in_seconds); } -void NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) { - ForIsolate(isolate)->FlushForegroundTasksInternal(); +bool NodePlatform::FlushForegroundTasks(v8::Isolate* isolate) { + return ForIsolate(isolate)->FlushForegroundTasksInternal(); } void NodePlatform::CancelPendingDelayedTasks(v8::Isolate* isolate) { @@ -348,4 +354,12 @@ void TaskQueue::Stop() { tasks_available_.Broadcast(scoped_lock); } +template +std::queue> TaskQueue::PopAll() { + Mutex::ScopedLock scoped_lock(lock_); + std::queue> result; + result.swap(task_queue_); + return result; +} + } // namespace node diff --git a/src/node_platform.h b/src/node_platform.h index b7546057871a1d..8f6ff89f491fe3 100644 --- a/src/node_platform.h +++ b/src/node_platform.h @@ -26,6 +26,7 @@ class TaskQueue { void Push(std::unique_ptr task); std::unique_ptr Pop(); std::unique_ptr BlockingPop(); + std::queue> PopAll(); void NotifyOfCompletion(); void BlockingDrain(); void Stop(); @@ -65,7 +66,9 @@ class PerIsolatePlatformData : void ref(); int unref(); - // Returns true iff work was dispatched or executed. + // Returns true if work was dispatched or executed. New tasks that are + // posted during flushing of the queue are postponed until the next + // flushing. bool FlushForegroundTasksInternal(); void CancelPendingDelayedTasks(); @@ -130,7 +133,10 @@ class NodePlatform : public MultiIsolatePlatform { double CurrentClockTimeMillis() override; v8::TracingController* GetTracingController() override; - void FlushForegroundTasks(v8::Isolate* isolate); + // Returns true if work was dispatched or executed. New tasks that are + // posted during flushing of the queue are postponed until the next + // flushing. + bool FlushForegroundTasks(v8::Isolate* isolate); void RegisterIsolate(IsolateData* isolate_data, uv_loop_t* loop) override; void UnregisterIsolate(IsolateData* isolate_data) override; diff --git a/test/cctest/test_platform.cc b/test/cctest/test_platform.cc new file mode 100644 index 00000000000000..876547480b7032 --- /dev/null +++ b/test/cctest/test_platform.cc @@ -0,0 +1,55 @@ +#include "node_internals.h" +#include "libplatform/libplatform.h" + +#include +#include "gtest/gtest.h" +#include "node_test_fixture.h" + +// This task increments the given run counter and reposts itself until the +// repost counter reaches zero. +class RepostingTask : public v8::Task { + public: + explicit RepostingTask(int repost_count, + int* run_count, + v8::Isolate* isolate, + node::NodePlatform* platform) + : repost_count_(repost_count), + run_count_(run_count), + isolate_(isolate), + platform_(platform) {} + + // v8::Task implementation + void Run() final { + ++*run_count_; + if (repost_count_ > 0) { + --repost_count_; + platform_->CallOnForegroundThread(isolate_, + new RepostingTask(repost_count_, run_count_, isolate_, platform_)); + } + } + + private: + int repost_count_; + int* run_count_; + v8::Isolate* isolate_; + node::NodePlatform* platform_; +}; + +class PlatformTest : public EnvironmentTestFixture {}; + +TEST_F(PlatformTest, SkipNewTasksInFlushForegroundTasks) { + v8::Isolate::Scope isolate_scope(isolate_); + const v8::HandleScope handle_scope(isolate_); + const Argv argv; + Env env {handle_scope, argv}; + int run_count = 0; + platform->CallOnForegroundThread( + isolate_, new RepostingTask(2, &run_count, isolate_, platform.get())); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(1, run_count); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(2, run_count); + EXPECT_TRUE(platform->FlushForegroundTasks(isolate_)); + EXPECT_EQ(3, run_count); + EXPECT_FALSE(platform->FlushForegroundTasks(isolate_)); +} From cac9923f612806c2fbd234493ccd64ec65c282df Mon Sep 17 00:00:00 2001 From: Hackzzila Date: Tue, 24 Apr 2018 21:14:12 -0500 Subject: [PATCH 05/76] doc: fix net.Socket link inconsistencies PR-URL: https://github.com/nodejs/node/pull/20271 Reviewed-By: Vse Mozhet Byt Reviewed-By: Rich Trott Reviewed-By: Trivikram Kamat Reviewed-By: Luigi Pinca --- doc/api/tty.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/api/tty.md b/doc/api/tty.md index 193005c017dda7..f8bc4feec3e86d 100644 --- a/doc/api/tty.md +++ b/doc/api/tty.md @@ -77,8 +77,8 @@ Note that `CTRL`+`C` will no longer cause a `SIGINT` when in this mode. added: v0.5.8 --> -The `tty.WriteStream` class is a subclass of `net.Socket` that represents the -writable side of a TTY. In normal circumstances, [`process.stdout`][] and +The `tty.WriteStream` class is a subclass of [`net.Socket`][] that represents +the writable side of a TTY. In normal circumstances, [`process.stdout`][] and [`process.stderr`][] will be the only `tty.WriteStream` instances created for a Node.js process and there should be no reason to create additional instances. From 90538fd3d8cde46e93ff0470e03593270024ae20 Mon Sep 17 00:00:00 2001 From: Zachary Vacura Date: Wed, 25 Apr 2018 01:33:01 -0500 Subject: [PATCH 06/76] doc: update pull request template in guide MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/20277 Refs: https://github.com/nodejs/node/pull/19125 Reviewed-By: Tobias Nießen Reviewed-By: Vse Mozhet Byt Reviewed-By: Luigi Pinca --- doc/guides/contributing/pull-requests.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/doc/guides/contributing/pull-requests.md b/doc/guides/contributing/pull-requests.md index f481a2cacb9f01..c248c1b9b6ec6f 100644 --- a/doc/guides/contributing/pull-requests.md +++ b/doc/guides/contributing/pull-requests.md @@ -334,9 +334,6 @@ Contributors guide: https://github.com/nodejs/node/blob/master/CONTRIBUTING.md - [ ] tests and/or benchmarks are included - [ ] documentation is changed or added - [ ] commit message follows [commit guidelines](https://github.com/nodejs/node/blob/master/doc/guides/contributing/pull-requests.md#commit-message-guidelines) - -#### Affected core subsystem(s) - ``` Please try to do your best at filling out the details, but feel free to skip From c378d61743336392c05160feef945d35ab7c780d Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 23 Apr 2018 22:31:20 -0400 Subject: [PATCH 07/76] test,n-api: re-write test_error in C PR-URL: https://github.com/nodejs/node/pull/20244 Reviewed-By: Daniel Bevenius Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/test_error/binding.gyp | 2 +- .../{test_error.cc => test_error.c} | 30 +++++++++---------- 2 files changed, 16 insertions(+), 16 deletions(-) rename test/addons-napi/test_error/{test_error.cc => test_error.c} (87%) diff --git a/test/addons-napi/test_error/binding.gyp b/test/addons-napi/test_error/binding.gyp index c2defd9551a31b..2923e15adca1a1 100644 --- a/test/addons-napi/test_error/binding.gyp +++ b/test/addons-napi/test_error/binding.gyp @@ -2,7 +2,7 @@ "targets": [ { "target_name": "test_error", - "sources": [ "test_error.cc" ] + "sources": [ "test_error.c" ] } ] } diff --git a/test/addons-napi/test_error/test_error.cc b/test/addons-napi/test_error/test_error.c similarity index 87% rename from test/addons-napi/test_error/test_error.cc rename to test/addons-napi/test_error/test_error.c index 4ab20bd7522a3b..1cad38098c9917 100644 --- a/test/addons-napi/test_error/test_error.cc +++ b/test/addons-napi/test_error/test_error.c @@ -4,7 +4,7 @@ napi_value checkError(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; - NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, nullptr, nullptr)); + NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); bool r; NAPI_CALL(env, napi_is_error(env, args[0], &r)); @@ -20,43 +20,43 @@ napi_value throwExistingError(napi_env env, napi_callback_info info) { napi_value error; NAPI_CALL(env, napi_create_string_utf8( env, "existing error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_error(env, nullptr, message, &error)); + NAPI_CALL(env, napi_create_error(env, NULL, message, &error)); NAPI_CALL(env, napi_throw(env, error)); - return nullptr; + return NULL; } napi_value throwError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_error(env, nullptr, "error")); - return nullptr; + NAPI_CALL(env, napi_throw_error(env, NULL, "error")); + return NULL; } napi_value throwRangeError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_range_error(env, nullptr, "range error")); - return nullptr; + NAPI_CALL(env, napi_throw_range_error(env, NULL, "range error")); + return NULL; } napi_value throwTypeError(napi_env env, napi_callback_info info) { - NAPI_CALL(env, napi_throw_type_error(env, nullptr, "type error")); - return nullptr; + NAPI_CALL(env, napi_throw_type_error(env, NULL, "type error")); + return NULL; } napi_value throwErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_error(env, "ERR_TEST_CODE", "Error [error]")); - return nullptr; + return NULL; } napi_value throwRangeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_range_error(env, "ERR_TEST_CODE", "RangeError [range error]")); - return nullptr; + return NULL; } napi_value throwTypeErrorCode(napi_env env, napi_callback_info info) { NAPI_CALL(env, napi_throw_type_error(env, "ERR_TEST_CODE", "TypeError [type error]")); - return nullptr; + return NULL; } @@ -65,7 +65,7 @@ napi_value createError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_error(env, NULL, message, &result)); return result; } @@ -74,7 +74,7 @@ napi_value createRangeError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "range error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_range_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_range_error(env, NULL, message, &result)); return result; } @@ -83,7 +83,7 @@ napi_value createTypeError(napi_env env, napi_callback_info info) { napi_value message; NAPI_CALL(env, napi_create_string_utf8( env, "type error", NAPI_AUTO_LENGTH, &message)); - NAPI_CALL(env, napi_create_type_error(env, nullptr, message, &result)); + NAPI_CALL(env, napi_create_type_error(env, NULL, message, &result)); return result; } From 33666c6964294e5f51a28d505d83ecaaa06d586d Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Mon, 23 Apr 2018 22:20:47 -0400 Subject: [PATCH 08/76] n-api,test: make methods static PR-URL: https://github.com/nodejs/node/pull/20243 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/1_hello_world/binding.c | 2 +- .../2_function_arguments/binding.c | 4 +-- test/addons-napi/3_callbacks/binding.c | 6 ++-- test/addons-napi/4_object_factory/binding.c | 4 +-- test/addons-napi/5_function_factory/binding.c | 6 ++-- test/addons-napi/test_array/test_array.c | 12 +++---- test/addons-napi/test_buffer/test_buffer.c | 16 ++++----- .../test_constructor/test_constructor.c | 12 +++---- .../test_constructor/test_constructor_name.c | 4 +-- .../test_conversions/test_conversions.c | 22 ++++++------ .../addons-napi/test_dataview/test_dataview.c | 6 ++-- .../test_env_sharing/compare_env.c | 4 +-- test/addons-napi/test_env_sharing/store_env.c | 2 +- test/addons-napi/test_fatal/test_fatal.c | 6 ++-- .../test_fatal_exception.c | 4 +-- .../addons-napi/test_function/test_function.c | 6 ++-- test/addons-napi/test_general/test_general.c | 36 +++++++++---------- .../test_handle_scope/test_handle_scope.c | 10 +++--- test/addons-napi/test_make_callback/binding.c | 3 +- test/addons-napi/test_new_target/binding.c | 8 ++--- test/addons-napi/test_number/test_number.c | 8 ++--- test/addons-napi/test_object/test_object.c | 20 +++++------ test/addons-napi/test_promise/test_promise.c | 9 ++--- .../test_properties/test_properties.c | 10 +++--- .../test_reference/test_reference.c | 21 +++++------ test/addons-napi/test_string/test_string.c | 21 +++++------ test/addons-napi/test_symbol/test_symbol.c | 6 ++-- .../test_typedarray/test_typedarray.c | 8 ++--- 28 files changed, 139 insertions(+), 137 deletions(-) diff --git a/test/addons-napi/1_hello_world/binding.c b/test/addons-napi/1_hello_world/binding.c index 6efc14ee66e18f..02cd5dd2f19418 100644 --- a/test/addons-napi/1_hello_world/binding.c +++ b/test/addons-napi/1_hello_world/binding.c @@ -2,7 +2,7 @@ #include "../common.h" #include -napi_value Method(napi_env env, napi_callback_info info) { +static napi_value Method(napi_env env, napi_callback_info info) { napi_value world; const char* str = "world"; size_t str_len = strlen(str); diff --git a/test/addons-napi/2_function_arguments/binding.c b/test/addons-napi/2_function_arguments/binding.c index c45ca0871db8ec..7d88c3d9e4ff19 100644 --- a/test/addons-napi/2_function_arguments/binding.c +++ b/test/addons-napi/2_function_arguments/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Add(napi_env env, napi_callback_info info) { +static napi_value Add(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -29,7 +29,7 @@ napi_value Add(napi_env env, napi_callback_info info) { return sum; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc = DECLARE_NAPI_PROPERTY("add", Add); NAPI_CALL(env, napi_define_properties(env, exports, 1, &desc)); return exports; diff --git a/test/addons-napi/3_callbacks/binding.c b/test/addons-napi/3_callbacks/binding.c index 7ebacf1d0653e9..1c0dd8126ce4ef 100644 --- a/test/addons-napi/3_callbacks/binding.c +++ b/test/addons-napi/3_callbacks/binding.c @@ -2,7 +2,7 @@ #include "../common.h" #include -napi_value RunCallback(napi_env env, napi_callback_info info) { +static napi_value RunCallback(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -34,7 +34,7 @@ napi_value RunCallback(napi_env env, napi_callback_info info) { return NULL; } -napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { +static napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value RunCallbackWithRecv(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor desc[2] = { DECLARE_NAPI_PROPERTY("RunCallback", RunCallback), DECLARE_NAPI_PROPERTY("RunCallbackWithRecv", RunCallbackWithRecv), diff --git a/test/addons-napi/4_object_factory/binding.c b/test/addons-napi/4_object_factory/binding.c index 38b8ec8e1cab48..0ed95e93512a0b 100644 --- a/test/addons-napi/4_object_factory/binding.c +++ b/test/addons-napi/4_object_factory/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value CreateObject(napi_env env, napi_callback_info info) { +static napi_value CreateObject(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -14,7 +14,7 @@ napi_value CreateObject(napi_env env, napi_callback_info info) { return obj; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function(env, "exports", -1, CreateObject, NULL, &exports)); return exports; diff --git a/test/addons-napi/5_function_factory/binding.c b/test/addons-napi/5_function_factory/binding.c index 8cc41f6aac5c3d..19460b9ddc55f2 100644 --- a/test/addons-napi/5_function_factory/binding.c +++ b/test/addons-napi/5_function_factory/binding.c @@ -1,20 +1,20 @@ #include #include "../common.h" -napi_value MyFunction(napi_env env, napi_callback_info info) { +static napi_value MyFunction(napi_env env, napi_callback_info info) { napi_value str; NAPI_CALL(env, napi_create_string_utf8(env, "hello world", -1, &str)); return str; } -napi_value CreateFunction(napi_env env, napi_callback_info info) { +static napi_value CreateFunction(napi_env env, napi_callback_info info) { napi_value fn; NAPI_CALL(env, napi_create_function(env, "theFunction", -1, MyFunction, NULL, &fn)); return fn; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function(env, "exports", -1, CreateFunction, NULL, &exports)); return exports; diff --git a/test/addons-napi/test_array/test_array.c b/test/addons-napi/test_array/test_array.c index f13867ca74f848..bd4f867c0c9117 100644 --- a/test/addons-napi/test_array/test_array.c +++ b/test/addons-napi/test_array/test_array.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value TestGetElement(napi_env env, napi_callback_info info) { +static napi_value TestGetElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value TestGetElement(napi_env env, napi_callback_info info) { return ret; } -napi_value TestHasElement(napi_env env, napi_callback_info info) { +static napi_value TestHasElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -84,7 +84,7 @@ napi_value TestHasElement(napi_env env, napi_callback_info info) { return ret; } -napi_value TestDeleteElement(napi_env env, napi_callback_info info) { +static napi_value TestDeleteElement(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; @@ -119,7 +119,7 @@ napi_value TestDeleteElement(napi_env env, napi_callback_info info) { return ret; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -147,7 +147,7 @@ napi_value New(napi_env env, napi_callback_info info) { return ret; } -napi_value NewWithLength(napi_env env, napi_callback_info info) { +static napi_value NewWithLength(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -169,7 +169,7 @@ napi_value NewWithLength(napi_env env, napi_callback_info info) { return ret; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("TestGetElement", TestGetElement), DECLARE_NAPI_PROPERTY("TestHasElement", TestHasElement), diff --git a/test/addons-napi/test_buffer/test_buffer.c b/test/addons-napi/test_buffer/test_buffer.c index 657eb7b3a051bf..552d280615739f 100644 --- a/test/addons-napi/test_buffer/test_buffer.c +++ b/test/addons-napi/test_buffer/test_buffer.c @@ -20,7 +20,7 @@ static void noopDeleter(napi_env env, void* data, void* finalize_hint) { deleterCallCount++; } -napi_value newBuffer(napi_env env, napi_callback_info info) { +static napi_value newBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; char* theCopy; const unsigned int kBufferSize = sizeof(theText); @@ -37,7 +37,7 @@ napi_value newBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value newExternalBuffer(napi_env env, napi_callback_info info) { +static napi_value newExternalBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; char* theCopy = strdup(theText); NAPI_ASSERT(env, theCopy, "Failed to copy static text for newExternalBuffer"); @@ -53,20 +53,20 @@ napi_value newExternalBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value getDeleterCallCount(napi_env env, napi_callback_info info) { +static napi_value getDeleterCallCount(napi_env env, napi_callback_info info) { napi_value callCount; NAPI_CALL(env, napi_create_int32(env, deleterCallCount, &callCount)); return callCount; } -napi_value copyBuffer(napi_env env, napi_callback_info info) { +static napi_value copyBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; NAPI_CALL(env, napi_create_buffer_copy( env, sizeof(theText), theText, NULL, &theBuffer)); return theBuffer; } -napi_value bufferHasInstance(napi_env env, napi_callback_info info) { +static napi_value bufferHasInstance(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value bufferHasInstance(napi_env env, napi_callback_info info) { return returnValue; } -napi_value bufferInfo(napi_env env, napi_callback_info info) { +static napi_value bufferInfo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -106,7 +106,7 @@ napi_value bufferInfo(napi_env env, napi_callback_info info) { return returnValue; } -napi_value staticBuffer(napi_env env, napi_callback_info info) { +static napi_value staticBuffer(napi_env env, napi_callback_info info) { napi_value theBuffer; NAPI_CALL( env, @@ -119,7 +119,7 @@ napi_value staticBuffer(napi_env env, napi_callback_info info) { return theBuffer; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value theValue; NAPI_CALL(env, diff --git a/test/addons-napi/test_constructor/test_constructor.c b/test/addons-napi/test_constructor/test_constructor.c index 4ee8323dd6ed40..8cc092049aef10 100644 --- a/test/addons-napi/test_constructor/test_constructor.c +++ b/test/addons-napi/test_constructor/test_constructor.c @@ -4,7 +4,7 @@ static double value_ = 1; static double static_value_ = 10; -napi_value GetValue(napi_env env, napi_callback_info info) { +static napi_value GetValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -16,7 +16,7 @@ napi_value GetValue(napi_env env, napi_callback_info info) { return number; } -napi_value SetValue(napi_env env, napi_callback_info info) { +static napi_value SetValue(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -28,7 +28,7 @@ napi_value SetValue(napi_env env, napi_callback_info info) { return NULL; } -napi_value Echo(napi_env env, napi_callback_info info) { +static napi_value Echo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -38,14 +38,14 @@ napi_value Echo(napi_env env, napi_callback_info info) { return args[0]; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); return _this; } -napi_value GetStaticValue(napi_env env, napi_callback_info info) { +static napi_value GetStaticValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -58,7 +58,7 @@ napi_value GetStaticValue(napi_env env, napi_callback_info info) { } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value number; NAPI_CALL(env, napi_create_double(env, value_, &number)); diff --git a/test/addons-napi/test_constructor/test_constructor_name.c b/test/addons-napi/test_constructor/test_constructor_name.c index a5c89791f0f0cd..b30ea4333747d3 100644 --- a/test/addons-napi/test_constructor/test_constructor_name.c +++ b/test/addons-napi/test_constructor/test_constructor_name.c @@ -3,14 +3,14 @@ napi_ref constructor_; -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); return _this; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value cons; NAPI_CALL(env, napi_define_class( env, "MyObject_Extra", 8, New, NULL, 0, NULL, &cons)); diff --git a/test/addons-napi/test_conversions/test_conversions.c b/test/addons-napi/test_conversions/test_conversions.c index 4f92bafa35b79d..845b7e7c56d7df 100644 --- a/test/addons-napi/test_conversions/test_conversions.c +++ b/test/addons-napi/test_conversions/test_conversions.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value AsBool(napi_env env, napi_callback_info info) { +static napi_value AsBool(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value AsBool(napi_env env, napi_callback_info info) { return output; } -napi_value AsInt32(napi_env env, napi_callback_info info) { +static napi_value AsInt32(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -29,7 +29,7 @@ napi_value AsInt32(napi_env env, napi_callback_info info) { return output; } -napi_value AsUInt32(napi_env env, napi_callback_info info) { +static napi_value AsUInt32(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -43,7 +43,7 @@ napi_value AsUInt32(napi_env env, napi_callback_info info) { return output; } -napi_value AsInt64(napi_env env, napi_callback_info info) { +static napi_value AsInt64(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -57,7 +57,7 @@ napi_value AsInt64(napi_env env, napi_callback_info info) { return output; } -napi_value AsDouble(napi_env env, napi_callback_info info) { +static napi_value AsDouble(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -71,7 +71,7 @@ napi_value AsDouble(napi_env env, napi_callback_info info) { return output; } -napi_value AsString(napi_env env, napi_callback_info info) { +static napi_value AsString(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -87,7 +87,7 @@ napi_value AsString(napi_env env, napi_callback_info info) { return output; } -napi_value ToBool(napi_env env, napi_callback_info info) { +static napi_value ToBool(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -98,7 +98,7 @@ napi_value ToBool(napi_env env, napi_callback_info info) { return output; } -napi_value ToNumber(napi_env env, napi_callback_info info) { +static napi_value ToNumber(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -109,7 +109,7 @@ napi_value ToNumber(napi_env env, napi_callback_info info) { return output; } -napi_value ToObject(napi_env env, napi_callback_info info) { +static napi_value ToObject(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -120,7 +120,7 @@ napi_value ToObject(napi_env env, napi_callback_info info) { return output; } -napi_value ToString(napi_env env, napi_callback_info info) { +static napi_value ToString(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -131,7 +131,7 @@ napi_value ToString(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("asBool", AsBool), DECLARE_NAPI_PROPERTY("asInt32", AsInt32), diff --git a/test/addons-napi/test_dataview/test_dataview.c b/test/addons-napi/test_dataview/test_dataview.c index 4d29ed07e9e6f7..8d29743522022f 100644 --- a/test/addons-napi/test_dataview/test_dataview.c +++ b/test/addons-napi/test_dataview/test_dataview.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value CreateDataView(napi_env env, napi_callback_info info) { +static napi_value CreateDataView(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args [3]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -49,7 +49,7 @@ napi_value CreateDataView(napi_env env, napi_callback_info info) { return output_dataview; } -napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { +static napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args [1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value CreateDataViewFromJSDataView(napi_env env, napi_callback_info info) { return output_dataview; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("CreateDataView", CreateDataView), DECLARE_NAPI_PROPERTY("CreateDataViewFromJSDataView", diff --git a/test/addons-napi/test_env_sharing/compare_env.c b/test/addons-napi/test_env_sharing/compare_env.c index 6a93ce52c64025..3326a34067219a 100644 --- a/test/addons-napi/test_env_sharing/compare_env.c +++ b/test/addons-napi/test_env_sharing/compare_env.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value compare(napi_env env, napi_callback_info info) { +static napi_value compare(napi_env env, napi_callback_info info) { napi_value external; size_t argc = 1; void* data; @@ -14,7 +14,7 @@ napi_value compare(napi_env env, napi_callback_info info) { return return_value; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { NAPI_CALL(env, napi_create_function( env, "exports", NAPI_AUTO_LENGTH, compare, NULL, &exports)); return exports; diff --git a/test/addons-napi/test_env_sharing/store_env.c b/test/addons-napi/test_env_sharing/store_env.c index 809f5f7a4b2eed..0559b178cba68b 100644 --- a/test/addons-napi/test_env_sharing/store_env.c +++ b/test/addons-napi/test_env_sharing/store_env.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value external; NAPI_CALL(env, napi_create_external(env, env, NULL, NULL, &external)); return external; diff --git a/test/addons-napi/test_fatal/test_fatal.c b/test/addons-napi/test_fatal/test_fatal.c index add8bebf3be7e3..b9248d40d49e6a 100644 --- a/test/addons-napi/test_fatal/test_fatal.c +++ b/test/addons-napi/test_fatal/test_fatal.c @@ -1,18 +1,18 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { napi_fatal_error("test_fatal::Test", NAPI_AUTO_LENGTH, "fatal message", NAPI_AUTO_LENGTH); return NULL; } -napi_value TestStringLength(napi_env env, napi_callback_info info) { +static napi_value TestStringLength(napi_env env, napi_callback_info info) { napi_fatal_error("test_fatal::TestStringLength", 16, "fatal message", 13); return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("Test", Test), DECLARE_NAPI_PROPERTY("TestStringLength", TestStringLength), diff --git a/test/addons-napi/test_fatal_exception/test_fatal_exception.c b/test/addons-napi/test_fatal_exception/test_fatal_exception.c index fd81c56d856db8..3cc810ccc0d10c 100644 --- a/test/addons-napi/test_fatal_exception/test_fatal_exception.c +++ b/test/addons-napi/test_fatal_exception/test_fatal_exception.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { napi_value err; size_t argc = 1; @@ -12,7 +12,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("Test", Test), }; diff --git a/test/addons-napi/test_function/test_function.c b/test/addons-napi/test_function/test_function.c index b0350e6ee22876..2c361933cfa071 100644 --- a/test/addons-napi/test_function/test_function.c +++ b/test/addons-napi/test_function/test_function.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value TestCallFunction(napi_env env, napi_callback_info info) { +static napi_value TestCallFunction(napi_env env, napi_callback_info info) { size_t argc = 10; napi_value args[10]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,11 +26,11 @@ napi_value TestCallFunction(napi_env env, napi_callback_info info) { return result; } -napi_value TestFunctionName(napi_env env, napi_callback_info info) { +static napi_value TestFunctionName(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value fn1; NAPI_CALL(env, napi_create_function( env, NULL, NAPI_AUTO_LENGTH, TestCallFunction, NULL, &fn1)); diff --git a/test/addons-napi/test_general/test_general.c b/test/addons-napi/test_general/test_general.c index 05cdd76e3c1e64..8f429f939fb89e 100644 --- a/test/addons-napi/test_general/test_general.c +++ b/test/addons-napi/test_general/test_general.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value testStrictEquals(napi_env env, napi_callback_info info) { +static napi_value testStrictEquals(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value testStrictEquals(napi_env env, napi_callback_info info) { return result; } -napi_value testGetPrototype(napi_env env, napi_callback_info info) { +static napi_value testGetPrototype(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,7 +26,7 @@ napi_value testGetPrototype(napi_env env, napi_callback_info info) { return result; } -napi_value testGetVersion(napi_env env, napi_callback_info info) { +static napi_value testGetVersion(napi_env env, napi_callback_info info) { uint32_t version; napi_value result; NAPI_CALL(env, napi_get_version(env, &version)); @@ -34,7 +34,7 @@ napi_value testGetVersion(napi_env env, napi_callback_info info) { return result; } -napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { +static napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { const napi_node_version* node_version; napi_value result, major, minor, patch, release; NAPI_CALL(env, napi_get_node_version(env, &node_version)); @@ -53,7 +53,7 @@ napi_value testGetNodeVersion(napi_env env, napi_callback_info info) { return result; } -napi_value doInstanceOf(napi_env env, napi_callback_info info) { +static napi_value doInstanceOf(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -67,19 +67,19 @@ napi_value doInstanceOf(napi_env env, napi_callback_info info) { return result; } -napi_value getNull(napi_env env, napi_callback_info info) { +static napi_value getNull(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_get_null(env, &result)); return result; } -napi_value getUndefined(napi_env env, napi_callback_info info) { +static napi_value getUndefined(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_get_undefined(env, &result)); return result; } -napi_value createNapiError(napi_env env, napi_callback_info info) { +static napi_value createNapiError(napi_env env, napi_callback_info info) { napi_value value; NAPI_CALL(env, napi_create_string_utf8(env, "xyz", 3, &value)); @@ -99,7 +99,7 @@ napi_value createNapiError(napi_env env, napi_callback_info info) { return NULL; } -napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { +static napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { const napi_extended_error_info *error_info = 0; NAPI_CALL(env, napi_get_last_error_info(env, &error_info)); @@ -110,7 +110,7 @@ napi_value testNapiErrorCleanup(napi_env env, napi_callback_info info) { return result; } -napi_value testNapiTypeof(napi_env env, napi_callback_info info) { +static napi_value testNapiTypeof(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -157,7 +157,7 @@ static void deref_item(napi_env env, void* data, void* hint) { deref_item_called = true; } -napi_value deref_item_was_called(napi_env env, napi_callback_info info) { +static napi_value deref_item_was_called(napi_env env, napi_callback_info info) { napi_value it_was_called; NAPI_CALL(env, napi_get_boolean(env, deref_item_called, &it_was_called)); @@ -165,7 +165,7 @@ napi_value deref_item_was_called(napi_env env, napi_callback_info info) { return it_was_called; } -napi_value wrap(napi_env env, napi_callback_info info) { +static napi_value wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value to_wrap; @@ -177,7 +177,7 @@ napi_value wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value remove_wrap(napi_env env, napi_callback_info info) { +static napi_value remove_wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value wrapped; void* data; @@ -193,7 +193,7 @@ static void test_finalize(napi_env env, void* data, void* hint) { finalize_called = true; } -napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { +static napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value js_object; @@ -203,7 +203,7 @@ napi_value test_finalize_wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value finalize_was_called(napi_env env, napi_callback_info info) { +static napi_value finalize_was_called(napi_env env, napi_callback_info info) { napi_value it_was_called; NAPI_CALL(env, napi_get_boolean(env, finalize_called, &it_was_called)); @@ -211,7 +211,7 @@ napi_value finalize_was_called(napi_env env, napi_callback_info info) { return it_was_called; } -napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { +static napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { napi_value result; int64_t adjustedValue; @@ -221,7 +221,7 @@ napi_value testAdjustExternalMemory(napi_env env, napi_callback_info info) { return result; } -napi_value testNapiRun(napi_env env, napi_callback_info info) { +static napi_value testNapiRun(napi_env env, napi_callback_info info) { napi_value script, result; size_t argc = 1; @@ -232,7 +232,7 @@ napi_value testNapiRun(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("testStrictEquals", testStrictEquals), DECLARE_NAPI_PROPERTY("testGetPrototype", testGetPrototype), diff --git a/test/addons-napi/test_handle_scope/test_handle_scope.c b/test/addons-napi/test_handle_scope/test_handle_scope.c index 31efbcf3dd4d7b..76f31f7882b61b 100644 --- a/test/addons-napi/test_handle_scope/test_handle_scope.c +++ b/test/addons-napi/test_handle_scope/test_handle_scope.c @@ -7,7 +7,7 @@ // the right right thing would be quite hard so we keep it // simple for now. -napi_value NewScope(napi_env env, napi_callback_info info) { +static napi_value NewScope(napi_env env, napi_callback_info info) { napi_handle_scope scope; napi_value output = NULL; @@ -17,7 +17,7 @@ napi_value NewScope(napi_env env, napi_callback_info info) { return NULL; } -napi_value NewScopeEscape(napi_env env, napi_callback_info info) { +static napi_value NewScopeEscape(napi_env env, napi_callback_info info) { napi_escapable_handle_scope scope; napi_value output = NULL; napi_value escapee = NULL; @@ -29,7 +29,7 @@ napi_value NewScopeEscape(napi_env env, napi_callback_info info) { return escapee; } -napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { +static napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { napi_escapable_handle_scope scope; napi_value output = NULL; napi_value escapee = NULL; @@ -44,7 +44,7 @@ napi_value NewScopeEscapeTwice(napi_env env, napi_callback_info info) { return NULL; } -napi_value NewScopeWithException(napi_env env, napi_callback_info info) { +static napi_value NewScopeWithException(napi_env env, napi_callback_info info) { napi_handle_scope scope; size_t argc; napi_value exception_function; @@ -68,7 +68,7 @@ napi_value NewScopeWithException(napi_env env, napi_callback_info info) { return NULL; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("NewScope", NewScope), DECLARE_NAPI_PROPERTY("NewScopeEscape", NewScopeEscape), diff --git a/test/addons-napi/test_make_callback/binding.c b/test/addons-napi/test_make_callback/binding.c index 23750f56b838fc..8eedd5b1b3b167 100644 --- a/test/addons-napi/test_make_callback/binding.c +++ b/test/addons-napi/test_make_callback/binding.c @@ -3,8 +3,7 @@ #define MAX_ARGUMENTS 10 -static -napi_value MakeCallback(napi_env env, napi_callback_info info) { +static napi_value MakeCallback(napi_env env, napi_callback_info info) { size_t argc = MAX_ARGUMENTS; size_t n; napi_value args[MAX_ARGUMENTS]; diff --git a/test/addons-napi/test_new_target/binding.c b/test/addons-napi/test_new_target/binding.c index a74d4bb2f877be..0c542ebaba693d 100644 --- a/test/addons-napi/test_new_target/binding.c +++ b/test/addons-napi/test_new_target/binding.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value BaseClass(napi_env env, napi_callback_info info) { +static napi_value BaseClass(napi_env env, napi_callback_info info) { napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); napi_value thisArg; @@ -22,7 +22,7 @@ napi_value BaseClass(napi_env env, napi_callback_info info) { return thisArg; } -napi_value Constructor(napi_env env, napi_callback_info info) { +static napi_value Constructor(napi_env env, napi_callback_info info) { bool result; napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); @@ -45,7 +45,7 @@ napi_value Constructor(napi_env env, napi_callback_info info) { return thisArg; } -napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { +static napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { napi_value newTargetArg; NAPI_CALL(env, napi_get_new_target(env, info, &newTargetArg)); @@ -56,7 +56,7 @@ napi_value OrdinaryFunction(napi_env env, napi_callback_info info) { return _true; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { const napi_property_descriptor desc[] = { DECLARE_NAPI_PROPERTY("BaseClass", BaseClass), DECLARE_NAPI_PROPERTY("OrdinaryFunction", OrdinaryFunction), diff --git a/test/addons-napi/test_number/test_number.c b/test/addons-napi/test_number/test_number.c index a1a70950083324..19b0ae83f051df 100644 --- a/test/addons-napi/test_number/test_number.c +++ b/test/addons-napi/test_number/test_number.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -23,7 +23,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return output; } -napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { +static napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -45,7 +45,7 @@ napi_value TestInt32Truncation(napi_env env, napi_callback_info info) { return output; } -napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { +static napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -67,7 +67,7 @@ napi_value TestInt64Truncation(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Test", Test), DECLARE_NAPI_PROPERTY("TestInt32Truncation", TestInt32Truncation), diff --git a/test/addons-napi/test_object/test_object.c b/test/addons-napi/test_object/test_object.c index ccf1573114a6f1..046f71fa414735 100644 --- a/test/addons-napi/test_object/test_object.c +++ b/test/addons-napi/test_object/test_object.c @@ -4,7 +4,7 @@ static int test_value = 3; -napi_value Get(napi_env env, napi_callback_info info) { +static napi_value Get(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -30,7 +30,7 @@ napi_value Get(napi_env env, napi_callback_info info) { return output; } -napi_value Set(napi_env env, napi_callback_info info) { +static napi_value Set(napi_env env, napi_callback_info info) { size_t argc = 3; napi_value args[3]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -57,7 +57,7 @@ napi_value Set(napi_env env, napi_callback_info info) { return valuetrue; } -napi_value Has(napi_env env, napi_callback_info info) { +static napi_value Has(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -85,7 +85,7 @@ napi_value Has(napi_env env, napi_callback_info info) { return ret; } -napi_value HasOwn(napi_env env, napi_callback_info info) { +static napi_value HasOwn(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -113,7 +113,7 @@ napi_value HasOwn(napi_env env, napi_callback_info info) { return ret; } -napi_value Delete(napi_env env, napi_callback_info info) { +static napi_value Delete(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; @@ -138,7 +138,7 @@ napi_value Delete(napi_env env, napi_callback_info info) { return ret; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { napi_value ret; NAPI_CALL(env, napi_create_object(env, &ret)); @@ -157,7 +157,7 @@ napi_value New(napi_env env, napi_callback_info info) { return ret; } -napi_value Inflate(napi_env env, napi_callback_info info) { +static napi_value Inflate(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -193,7 +193,7 @@ napi_value Inflate(napi_env env, napi_callback_info info) { return obj; } -napi_value Wrap(napi_env env, napi_callback_info info) { +static napi_value Wrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -202,7 +202,7 @@ napi_value Wrap(napi_env env, napi_callback_info info) { return NULL; } -napi_value Unwrap(napi_env env, napi_callback_info info) { +static napi_value Unwrap(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -216,7 +216,7 @@ napi_value Unwrap(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Get", Get), DECLARE_NAPI_PROPERTY("Set", Set), diff --git a/test/addons-napi/test_promise/test_promise.c b/test/addons-napi/test_promise/test_promise.c index aa89c022bc1a4a..3e2ec48572af4c 100644 --- a/test/addons-napi/test_promise/test_promise.c +++ b/test/addons-napi/test_promise/test_promise.c @@ -3,7 +3,7 @@ napi_deferred deferred = NULL; -napi_value createPromise(napi_env env, napi_callback_info info) { +static napi_value createPromise(napi_env env, napi_callback_info info) { napi_value promise; // We do not overwrite an existing deferred. @@ -16,7 +16,8 @@ napi_value createPromise(napi_env env, napi_callback_info info) { return promise; } -napi_value concludeCurrentPromise(napi_env env, napi_callback_info info) { +static napi_value +concludeCurrentPromise(napi_env env, napi_callback_info info) { napi_value argv[2]; size_t argc = 2; bool resolution; @@ -34,7 +35,7 @@ napi_value concludeCurrentPromise(napi_env env, napi_callback_info info) { return NULL; } -napi_value isPromise(napi_env env, napi_callback_info info) { +static napi_value isPromise(napi_env env, napi_callback_info info) { napi_value promise, result; size_t argc = 1; bool is_promise; @@ -46,7 +47,7 @@ napi_value isPromise(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("createPromise", createPromise), DECLARE_NAPI_PROPERTY("concludeCurrentPromise", concludeCurrentPromise), diff --git a/test/addons-napi/test_properties/test_properties.c b/test/addons-napi/test_properties/test_properties.c index a95c7013c2cabb..2754812f4dad27 100644 --- a/test/addons-napi/test_properties/test_properties.c +++ b/test/addons-napi/test_properties/test_properties.c @@ -3,7 +3,7 @@ static double value_ = 1; -napi_value GetValue(napi_env env, napi_callback_info info) { +static napi_value GetValue(napi_env env, napi_callback_info info) { size_t argc = 0; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, NULL, NULL, NULL)); @@ -15,7 +15,7 @@ napi_value GetValue(napi_env env, napi_callback_info info) { return number; } -napi_value SetValue(napi_env env, napi_callback_info info) { +static napi_value SetValue(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -27,7 +27,7 @@ napi_value SetValue(napi_env env, napi_callback_info info) { return NULL; } -napi_value Echo(napi_env env, napi_callback_info info) { +static napi_value Echo(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -37,7 +37,7 @@ napi_value Echo(napi_env env, napi_callback_info info) { return args[0]; } -napi_value HasNamedProperty(napi_env env, napi_callback_info info) { +static napi_value HasNamedProperty(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -59,7 +59,7 @@ napi_value HasNamedProperty(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_value number; NAPI_CALL(env, napi_create_double(env, value_, &number)); diff --git a/test/addons-napi/test_reference/test_reference.c b/test/addons-napi/test_reference/test_reference.c index f34adc6693b6fe..641b1cb82ba8e1 100644 --- a/test/addons-napi/test_reference/test_reference.c +++ b/test/addons-napi/test_reference/test_reference.c @@ -5,7 +5,7 @@ static int test_value = 1; static int finalize_count = 0; static napi_ref test_reference = NULL; -napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { +static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_create_int32(env, finalize_count, &result)); return result; @@ -18,7 +18,7 @@ void FinalizeExternal(napi_env env, void* data, void* hint) { finalize_count++; } -napi_value CreateExternal(napi_env env, napi_callback_info info) { +static napi_value CreateExternal(napi_env env, napi_callback_info info) { int* data = &test_value; napi_value result; @@ -33,7 +33,8 @@ napi_value CreateExternal(napi_env env, napi_callback_info info) { return result; } -napi_value CreateExternalWithFinalize(napi_env env, napi_callback_info info) { +static napi_value +CreateExternalWithFinalize(napi_env env, napi_callback_info info) { napi_value result; NAPI_CALL(env, napi_create_external(env, @@ -46,7 +47,7 @@ napi_value CreateExternalWithFinalize(napi_env env, napi_callback_info info) { return result; } -napi_value CheckExternal(napi_env env, napi_callback_info info) { +static napi_value CheckExternal(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value arg; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, &arg, NULL, NULL)); @@ -67,7 +68,7 @@ napi_value CheckExternal(napi_env env, napi_callback_info info) { return NULL; } -napi_value CreateReference(napi_env env, napi_callback_info info) { +static napi_value CreateReference(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference == NULL, "The test allows only one reference at a time."); @@ -88,7 +89,7 @@ napi_value CreateReference(napi_env env, napi_callback_info info) { return NULL; } -napi_value DeleteReference(napi_env env, napi_callback_info info) { +static napi_value DeleteReference(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -97,7 +98,7 @@ napi_value DeleteReference(napi_env env, napi_callback_info info) { return NULL; } -napi_value IncrementRefcount(napi_env env, napi_callback_info info) { +static napi_value IncrementRefcount(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -109,7 +110,7 @@ napi_value IncrementRefcount(napi_env env, napi_callback_info info) { return result; } -napi_value DecrementRefcount(napi_env env, napi_callback_info info) { +static napi_value DecrementRefcount(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -121,7 +122,7 @@ napi_value DecrementRefcount(napi_env env, napi_callback_info info) { return result; } -napi_value GetReferenceValue(napi_env env, napi_callback_info info) { +static napi_value GetReferenceValue(napi_env env, napi_callback_info info) { NAPI_ASSERT(env, test_reference != NULL, "A reference must have been created."); @@ -130,7 +131,7 @@ napi_value GetReferenceValue(napi_env env, napi_callback_info info) { return result; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_GETTER("finalizeCount", GetFinalizeCount), DECLARE_NAPI_PROPERTY("createExternal", CreateExternal), diff --git a/test/addons-napi/test_string/test_string.c b/test/addons-napi/test_string/test_string.c index 99a3f7d3545a20..4e6da7bf86849f 100644 --- a/test/addons-napi/test_string/test_string.c +++ b/test/addons-napi/test_string/test_string.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value TestLatin1(napi_env env, napi_callback_info info) { +static napi_value TestLatin1(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -28,7 +28,7 @@ napi_value TestLatin1(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf8(napi_env env, napi_callback_info info) { +static napi_value TestUtf8(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -54,7 +54,7 @@ napi_value TestUtf8(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf16(napi_env env, napi_callback_info info) { +static napi_value TestUtf16(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -80,7 +80,8 @@ napi_value TestUtf16(napi_env env, napi_callback_info info) { return output; } -napi_value TestLatin1Insufficient(napi_env env, napi_callback_info info) { +static napi_value +TestLatin1Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -106,7 +107,7 @@ napi_value TestLatin1Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { +static napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -132,7 +133,7 @@ napi_value TestUtf8Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { +static napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -158,7 +159,7 @@ napi_value TestUtf16Insufficient(napi_env env, napi_callback_info info) { return output; } -napi_value Utf16Length(napi_env env, napi_callback_info info) { +static napi_value Utf16Length(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -180,7 +181,7 @@ napi_value Utf16Length(napi_env env, napi_callback_info info) { return output; } -napi_value Utf8Length(napi_env env, napi_callback_info info) { +static napi_value Utf8Length(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -202,7 +203,7 @@ napi_value Utf8Length(napi_env env, napi_callback_info info) { return output; } -napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { +static napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { napi_value output; if (SIZE_MAX > INT_MAX) { NAPI_CALL(env, napi_create_string_utf8(env, "", ((size_t)INT_MAX) + 1, &output)); @@ -215,7 +216,7 @@ napi_value TestLargeUtf8(napi_env env, napi_callback_info info) { return output; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("TestLatin1", TestLatin1), DECLARE_NAPI_PROPERTY("TestLatin1Insufficient", TestLatin1Insufficient), diff --git a/test/addons-napi/test_symbol/test_symbol.c b/test/addons-napi/test_symbol/test_symbol.c index c91b6ae54f4932..18cb4b405fb76d 100644 --- a/test/addons-napi/test_symbol/test_symbol.c +++ b/test/addons-napi/test_symbol/test_symbol.c @@ -1,7 +1,7 @@ #include #include "../common.h" -napi_value Test(napi_env env, napi_callback_info info) { +static napi_value Test(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -26,7 +26,7 @@ napi_value Test(napi_env env, napi_callback_info info) { return output; } -napi_value New(napi_env env, napi_callback_info info) { +static napi_value New(napi_env env, napi_callback_info info) { size_t argc = 1; napi_value args[1]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -48,7 +48,7 @@ napi_value New(napi_env env, napi_callback_info info) { return symbol; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor properties[] = { DECLARE_NAPI_PROPERTY("New", New), }; diff --git a/test/addons-napi/test_typedarray/test_typedarray.c b/test/addons-napi/test_typedarray/test_typedarray.c index 2758a6f53298fe..a0ac02665864f1 100644 --- a/test/addons-napi/test_typedarray/test_typedarray.c +++ b/test/addons-napi/test_typedarray/test_typedarray.c @@ -2,7 +2,7 @@ #include #include "../common.h" -napi_value Multiply(napi_env env, napi_callback_info info) { +static napi_value Multiply(napi_env env, napi_callback_info info) { size_t argc = 2; napi_value args[2]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -73,7 +73,7 @@ napi_value Multiply(napi_env env, napi_callback_info info) { return output_array; } -napi_value External(napi_env env, napi_callback_info info) { +static napi_value External(napi_env env, napi_callback_info info) { static int8_t externalData[] = {0, 1, 2}; napi_value output_buffer; @@ -96,7 +96,7 @@ napi_value External(napi_env env, napi_callback_info info) { return output_array; } -napi_value CreateTypedArray(napi_env env, napi_callback_info info) { +static napi_value CreateTypedArray(napi_env env, napi_callback_info info) { size_t argc = 4; napi_value args[4]; NAPI_CALL(env, napi_get_cb_info(env, info, &argc, args, NULL, NULL)); @@ -165,7 +165,7 @@ napi_value CreateTypedArray(napi_env env, napi_callback_info info) { return output_array; } -napi_value Init(napi_env env, napi_value exports) { +static napi_value Init(napi_env env, napi_value exports) { napi_property_descriptor descriptors[] = { DECLARE_NAPI_PROPERTY("Multiply", Multiply), DECLARE_NAPI_PROPERTY("External", External), From 5aaee4829c2e0b8680a4707d147a688553013264 Mon Sep 17 00:00:00 2001 From: William Cohen Date: Thu, 19 Apr 2018 10:15:25 -0400 Subject: [PATCH 09/76] src: fix Systemtap node_gc_stop probe The process("node").mark("gc__stop") is actually process("node").mark("gc__done"). Use the proper name so that a developer can use SystemTap to determine the duration of garbage collection. PR-URL: https://github.com/nodejs/node/pull/20152 Reviewed-By: Ben Noordhuis Reviewed-By: Matheus Marchini Reviewed-By: Richard Lau --- src/node.stp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/node.stp b/src/node.stp index 3369968c205146..ebc40d574fc2be 100644 --- a/src/node.stp +++ b/src/node.stp @@ -125,7 +125,7 @@ probe node_gc_start = process("node").mark("gc__start") flags); } -probe node_gc_stop = process("node").mark("gc__stop") +probe node_gc_stop = process("node").mark("gc__done") { scavenge = 1 << 0; compact = 1 << 1; From 23f345e9d395705b27384b28e32ee63a0258ccbf Mon Sep 17 00:00:00 2001 From: Joyee Cheung Date: Thu, 19 Apr 2018 18:41:33 +0800 Subject: [PATCH 10/76] src: assign ERR_SCRIPT_EXECUTION_* codes in C++ MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Also modifies the error messages so they include more information and are more consistent. - The message of ERR_SCRIPT_EXECUTION_INTERRUPTED now mentions SIGINT and the trailing period is dropped for consistency. - Added ERR_SCRIPT_EXECUTION_TIMEOUT and include the timeout in the message. PR-URL: https://github.com/nodejs/node/pull/20147 Reviewed-By: Ruben Bridgewater Reviewed-By: Michaël Zasso Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Gus Caplan Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- doc/api/errors.md | 4 ++ lib/internal/errors.js | 2 +- src/module_wrap.cc | 4 +- src/node_contextify.cc | 5 +- src/node_errors.h | 17 +++++- test/parallel/test-repl-sigint-nested-eval.js | 6 +- test/parallel/test-repl-sigint.js | 5 +- test/parallel/test-repl-top-level-await.js | 2 +- .../test-vm-sigint-existing-handler.js | 8 ++- test/parallel/test-vm-sigint.js | 8 ++- test/parallel/test-vm-timeout.js | 59 ++++++++++++------- test/sequential/test-vm-timeout-rethrow.js | 2 +- 12 files changed, 83 insertions(+), 39 deletions(-) diff --git a/doc/api/errors.md b/doc/api/errors.md index df81718e7d7fb0..ff317f676a8881 100644 --- a/doc/api/errors.md +++ b/doc/api/errors.md @@ -1371,6 +1371,10 @@ An attempt was made to `require()` an [ES6 module][]. Script execution was interrupted by `SIGINT` (For example, when Ctrl+C was pressed). +### ERR_SCRIPT_EXECUTION_TIMEOUT + +Script execution timed out, possibly due to bugs in the script being executed. + ### ERR_SERVER_ALREADY_LISTEN diff --git a/lib/internal/errors.js b/lib/internal/errors.js index 09f58506c44ea0..e7eb3bd133813a 100644 --- a/lib/internal/errors.js +++ b/lib/internal/errors.js @@ -952,7 +952,7 @@ E('ERR_NO_LONGER_SUPPORTED', '%s is no longer supported', Error); E('ERR_OUT_OF_RANGE', outOfRange, RangeError); E('ERR_REQUIRE_ESM', 'Must use import to load ES Module: %s', Error); E('ERR_SCRIPT_EXECUTION_INTERRUPTED', - 'Script execution was interrupted by `SIGINT`.', Error); + 'Script execution was interrupted by `SIGINT`', Error); E('ERR_SERVER_ALREADY_LISTEN', 'Listen method has been called more than once without closing.', Error); E('ERR_SERVER_NOT_RUNNING', 'Server is not running.', Error); diff --git a/src/module_wrap.cc b/src/module_wrap.cc index 9bcdb4dce75ff2..f88c113ae0b93f 100644 --- a/src/module_wrap.cc +++ b/src/module_wrap.cc @@ -286,9 +286,9 @@ void ModuleWrap::Evaluate(const FunctionCallbackInfo& args) { // which this timeout is nested, so check whether one of the watchdogs // from this invocation is responsible for termination. if (timed_out) { - env->ThrowError("Script execution timed out."); + THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout); } else if (received_signal) { - env->ThrowError("Script execution interrupted."); + THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env); } } diff --git a/src/node_contextify.cc b/src/node_contextify.cc index e07d5ebcd29d0d..ca58d1897e68b2 100644 --- a/src/node_contextify.cc +++ b/src/node_contextify.cc @@ -19,6 +19,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE // USE OR OTHER DEALINGS IN THE SOFTWARE. +#include "node_errors.h" #include "node_internals.h" #include "node_watchdog.h" #include "base_object-inl.h" @@ -858,9 +859,9 @@ class ContextifyScript : public BaseObject { // which this timeout is nested, so check whether one of the watchdogs // from this invocation is responsible for termination. if (timed_out) { - env->ThrowError("Script execution timed out."); + node::THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, timeout); } else if (received_signal) { - env->ThrowError("Script execution interrupted."); + node::THROW_ERR_SCRIPT_EXECUTION_INTERRUPTED(env); } } diff --git a/src/node_errors.h b/src/node_errors.h index 0f91872474148d..eb120c62807cf6 100644 --- a/src/node_errors.h +++ b/src/node_errors.h @@ -8,6 +8,10 @@ #include "env-inl.h" #include "v8.h" +// Use ostringstream to print exact-width integer types +// because the format specifiers are not available on AIX. +#include + namespace node { // Helpers to construct errors similar to the ones provided by @@ -24,6 +28,8 @@ namespace node { V(ERR_MEMORY_ALLOCATION_FAILED, Error) \ V(ERR_MISSING_ARGS, TypeError) \ V(ERR_MISSING_MODULE, Error) \ + V(ERR_SCRIPT_EXECUTION_INTERRUPTED, Error) \ + V(ERR_SCRIPT_EXECUTION_TIMEOUT, Error) \ V(ERR_STRING_TOO_LONG, Error) \ V(ERR_BUFFER_TOO_LARGE, Error) @@ -49,7 +55,9 @@ namespace node { #define PREDEFINED_ERROR_MESSAGES(V) \ V(ERR_INDEX_OUT_OF_RANGE, "Index out of range") \ - V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") + V(ERR_MEMORY_ALLOCATION_FAILED, "Failed to allocate memory") \ + V(ERR_SCRIPT_EXECUTION_INTERRUPTED, \ + "Script execution was interrupted by `SIGINT`") #define V(code, message) \ inline v8::Local code(v8::Isolate* isolate) { \ @@ -62,6 +70,13 @@ namespace node { #undef V // Errors with predefined non-static messages +inline void THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(Environment* env, + int64_t timeout) { + std::ostringstream message; + message << "Script execution timed out after "; + message << timeout << "ms"; + THROW_ERR_SCRIPT_EXECUTION_TIMEOUT(env, message.str().c_str()); +} inline v8::Local ERR_BUFFER_TOO_LARGE(v8::Isolate *isolate) { char message[128]; diff --git a/test/parallel/test-repl-sigint-nested-eval.js b/test/parallel/test-repl-sigint-nested-eval.js index 7f15b7dfeb8b9d..ea07393527b828 100644 --- a/test/parallel/test-repl-sigint-nested-eval.js +++ b/test/parallel/test-repl-sigint-nested-eval.js @@ -34,10 +34,10 @@ child.stdout.once('data', common.mustCall(() => { })); child.on('close', function(code) { - assert.strictEqual(code, 0); + const expected = 'Script execution was interrupted by `SIGINT`'; assert.ok( - stdout.includes('Script execution interrupted.'), - `Expected stdout to contain "Script execution interrupted.", got ${stdout}` + stdout.includes(expected), + `Expected stdout to contain "${expected}", got ${stdout}` ); assert.ok( stdout.includes('foobar'), diff --git a/test/parallel/test-repl-sigint.js b/test/parallel/test-repl-sigint.js index 818111c39bf578..14cafd0463709f 100644 --- a/test/parallel/test-repl-sigint.js +++ b/test/parallel/test-repl-sigint.js @@ -35,9 +35,10 @@ child.stdout.once('data', common.mustCall(() => { child.on('close', function(code) { assert.strictEqual(code, 0); + const expected = 'Script execution was interrupted by `SIGINT`'; assert.ok( - stdout.includes('Script execution interrupted.\n'), - `Expected stdout to contain "Script execution interrupted.", got ${stdout}` + stdout.includes(expected), + `Expected stdout to contain "${expected}", got ${stdout}` ); assert.ok( stdout.includes('42042\n'), diff --git a/test/parallel/test-repl-top-level-await.js b/test/parallel/test-repl-top-level-await.js index 91f5758c210a36..5a07f5ced14450 100644 --- a/test/parallel/test-repl-top-level-await.js +++ b/test/parallel/test-repl-top-level-await.js @@ -161,7 +161,7 @@ async function ctrlCTest() { ]), [ 'await timeout(100000)\r', 'Thrown: Error [ERR_SCRIPT_EXECUTION_INTERRUPTED]: ' + - 'Script execution was interrupted by `SIGINT`.', + 'Script execution was interrupted by `SIGINT`', PROMPT ]); } diff --git a/test/parallel/test-vm-sigint-existing-handler.js b/test/parallel/test-vm-sigint-existing-handler.js index 79a4d556ac05d6..13fccd9637c7fb 100644 --- a/test/parallel/test-vm-sigint-existing-handler.js +++ b/test/parallel/test-vm-sigint-existing-handler.js @@ -36,8 +36,12 @@ if (process.argv[2] === 'child') { []; const options = { breakOnSigint: true }; - assert.throws(() => { vm[method](script, ...args, options); }, - /^Error: Script execution interrupted\.$/); + common.expectsError( + () => { vm[method](script, ...args, options); }, + { + code: 'ERR_SCRIPT_EXECUTION_INTERRUPTED', + message: 'Script execution was interrupted by `SIGINT`' + }); assert.strictEqual(firstHandlerCalled, 0); assert.strictEqual(onceHandlerCalled, 0); diff --git a/test/parallel/test-vm-sigint.js b/test/parallel/test-vm-sigint.js index 9935b3d04b57a8..0fecfbace68049 100644 --- a/test/parallel/test-vm-sigint.js +++ b/test/parallel/test-vm-sigint.js @@ -24,8 +24,12 @@ if (process.argv[2] === 'child') { for (let i = 0; i < listeners; i++) process.on('SIGINT', common.mustNotCall()); - assert.throws(() => { vm[method](script, ...args, options); }, - /^Error: Script execution interrupted\.$/); + common.expectsError( + () => { vm[method](script, ...args, options); }, + { + code: 'ERR_SCRIPT_EXECUTION_INTERRUPTED', + message: 'Script execution was interrupted by `SIGINT`' + }); return; } diff --git a/test/parallel/test-vm-timeout.js b/test/parallel/test-vm-timeout.js index 859992e99ba36f..426d1e06925514 100644 --- a/test/parallel/test-vm-timeout.js +++ b/test/parallel/test-vm-timeout.js @@ -25,35 +25,50 @@ const assert = require('assert'); const vm = require('vm'); // Timeout of 100ms executing endless loop -assert.throws(function() { - vm.runInThisContext('while(true) {}', { timeout: 100 }); -}, /^Error: Script execution timed out\.$/); +assert.throws( + function() { + vm.runInThisContext('while(true) {}', { timeout: 100 }); + }, + { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 100ms' + }); // Timeout of 1000ms, script finishes first vm.runInThisContext('', { timeout: 1000 }); // Nested vm timeouts, inner timeout propagates out -assert.throws(function() { - const context = { - log: console.log, - runInVM: function(timeout) { - vm.runInNewContext('while(true) {}', context, { timeout }); - } - }; - vm.runInNewContext('runInVM(10)', context, { timeout: 10000 }); - throw new Error('Test 5 failed'); -}, /Script execution timed out\./); +assert.throws( + function() { + const context = { + log: console.log, + runInVM: function(timeout) { + vm.runInNewContext('while(true) {}', context, { timeout }); + } + }; + vm.runInNewContext('runInVM(10)', context, { timeout: 10000 }); + throw new Error('Test 5 failed'); + }, + { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 10ms' + }); // Nested vm timeouts, outer timeout is shorter and fires first. -assert.throws(function() { - const context = { - runInVM: function(timeout) { - vm.runInNewContext('while(true) {}', context, { timeout }); - } - }; - vm.runInNewContext('runInVM(10000)', context, { timeout: 100 }); - throw new Error('Test 6 failed'); -}, /Script execution timed out\./); +assert.throws( + function() { + const context = { + runInVM: function(timeout) { + vm.runInNewContext('while(true) {}', context, { timeout }); + } + }; + vm.runInNewContext('runInVM(10000)', context, { timeout: 100 }); + throw new Error('Test 6 failed'); + }, + { + code: 'ERR_SCRIPT_EXECUTION_TIMEOUT', + message: 'Script execution timed out after 100ms' + }); // Nested vm timeouts, inner script throws an error. assert.throws(function() { diff --git a/test/sequential/test-vm-timeout-rethrow.js b/test/sequential/test-vm-timeout-rethrow.js index a7aa83e513d03c..c38460c4c89925 100644 --- a/test/sequential/test-vm-timeout-rethrow.js +++ b/test/sequential/test-vm-timeout-rethrow.js @@ -39,6 +39,6 @@ if (process.argv[2] === 'child') { }); process.on('exit', function() { - assert.ok(/Script execution timed out/.test(err)); + assert.ok(/Script execution timed out after 1ms/.test(err)); }); } From 29eb3cb0a285dcb2a511f76735c89455a31328fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Mon, 23 Apr 2018 16:14:22 +0200 Subject: [PATCH 11/76] crypto: use kNoAuthTagLength in InitAuthenticated PR-URL: https://github.com/nodejs/node/pull/20225 Refs: https://github.com/nodejs/node/pull/20039 Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius Reviewed-By: Ben Noordhuis --- src/node_crypto.cc | 30 +++++++++++++++++++++--------- src/node_crypto.h | 7 ++++--- 2 files changed, 25 insertions(+), 12 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 04a5924c097296..0eac04bebbf9c8 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2629,7 +2629,7 @@ void CipherBase::New(const FunctionCallbackInfo& args) { void CipherBase::Init(const char* cipher_type, const char* key_buf, int key_buf_len, - int auth_tag_len) { + unsigned int auth_tag_len) { HandleScope scope(env()->isolate()); #ifdef NODE_FIPS_MODE @@ -2700,10 +2700,16 @@ void CipherBase::Init(const FunctionCallbackInfo& args) { const node::Utf8Value cipher_type(args.GetIsolate(), args[0]); const char* key_buf = Buffer::Data(args[1]); ssize_t key_buf_len = Buffer::Length(args[1]); - CHECK(args[2]->IsInt32()); + // Don't assign to cipher->auth_tag_len_ directly; the value might not // represent a valid length at this point. - int auth_tag_len = args[2].As()->Value(); + unsigned int auth_tag_len; + if (args[2]->IsUint32()) { + auth_tag_len = args[2].As()->Value(); + } else { + CHECK(args[2]->IsInt32() && args[2].As()->Value() == -1); + auth_tag_len = kNoAuthTagLength; + } cipher->Init(*cipher_type, key_buf, key_buf_len, auth_tag_len); } @@ -2714,7 +2720,7 @@ void CipherBase::InitIv(const char* cipher_type, int key_len, const char* iv, int iv_len, - int auth_tag_len) { + unsigned int auth_tag_len) { HandleScope scope(env()->isolate()); const EVP_CIPHER* const cipher = EVP_get_cipherbyname(cipher_type); @@ -2788,10 +2794,16 @@ void CipherBase::InitIv(const FunctionCallbackInfo& args) { iv_buf = Buffer::Data(args[2]); iv_len = Buffer::Length(args[2]); } - CHECK(args[3]->IsInt32()); + // Don't assign to cipher->auth_tag_len_ directly; the value might not // represent a valid length at this point. - int auth_tag_len = args[3].As()->Value(); + unsigned int auth_tag_len; + if (args[3]->IsUint32()) { + auth_tag_len = args[3].As()->Value(); + } else { + CHECK(args[3]->IsInt32() && args[3].As()->Value() == -1); + auth_tag_len = kNoAuthTagLength; + } cipher->InitIv(*cipher_type, key_buf, key_len, iv_buf, iv_len, auth_tag_len); } @@ -2802,7 +2814,7 @@ static bool IsValidGCMTagLength(unsigned int tag_len) { } bool CipherBase::InitAuthenticated(const char *cipher_type, int iv_len, - int auth_tag_len) { + unsigned int auth_tag_len) { CHECK(IsAuthenticatedMode()); // TODO(tniessen) Use EVP_CTRL_AEAD_SET_IVLEN when migrating to OpenSSL 1.1.0 @@ -2815,7 +2827,7 @@ bool CipherBase::InitAuthenticated(const char *cipher_type, int iv_len, const int mode = EVP_CIPHER_CTX_mode(ctx_); if (mode == EVP_CIPH_CCM_MODE) { - if (auth_tag_len < 0) { + if (auth_tag_len == kNoAuthTagLength) { char msg[128]; snprintf(msg, sizeof(msg), "authTagLength required for %s", cipher_type); env()->ThrowError(msg); @@ -2850,7 +2862,7 @@ bool CipherBase::InitAuthenticated(const char *cipher_type, int iv_len, } else { CHECK_EQ(mode, EVP_CIPH_GCM_MODE); - if (auth_tag_len >= 0) { + if (auth_tag_len != kNoAuthTagLength) { if (!IsValidGCMTagLength(auth_tag_len)) { char msg[50]; snprintf(msg, sizeof(msg), diff --git a/src/node_crypto.h b/src/node_crypto.h index 3c166f5dcc89fc..a706c2805726bf 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -364,14 +364,15 @@ class CipherBase : public BaseObject { void Init(const char* cipher_type, const char* key_buf, int key_buf_len, - int auth_tag_len); + unsigned int auth_tag_len); void InitIv(const char* cipher_type, const char* key, int key_len, const char* iv, int iv_len, - int auth_tag_len); - bool InitAuthenticated(const char *cipher_type, int iv_len, int auth_tag_len); + unsigned int auth_tag_len); + bool InitAuthenticated(const char *cipher_type, int iv_len, + unsigned int auth_tag_len); bool CheckCCMMessageLength(int message_len); UpdateResult Update(const char* data, int len, unsigned char** out, int* out_len); From 79ea56f628b3279715fb07140aa1a2ec9aaab6be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Tue, 24 Apr 2018 16:21:27 +0200 Subject: [PATCH 12/76] crypto: add using directives for v8::Int32, Uint32 PR-URL: https://github.com/nodejs/node/pull/20225 Refs: https://github.com/nodejs/node/pull/20039 Reviewed-By: James M Snell Reviewed-By: Daniel Bevenius Reviewed-By: Ben Noordhuis --- src/node_crypto.cc | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 0eac04bebbf9c8..d1e1703d2c8ba7 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -72,6 +72,7 @@ using v8::External; using v8::FunctionCallbackInfo; using v8::FunctionTemplate; using v8::HandleScope; +using v8::Int32; using v8::Integer; using v8::Isolate; using v8::Local; @@ -84,6 +85,7 @@ using v8::PropertyAttribute; using v8::ReadOnly; using v8::Signature; using v8::String; +using v8::Uint32; using v8::Value; @@ -2705,9 +2707,9 @@ void CipherBase::Init(const FunctionCallbackInfo& args) { // represent a valid length at this point. unsigned int auth_tag_len; if (args[2]->IsUint32()) { - auth_tag_len = args[2].As()->Value(); + auth_tag_len = args[2].As()->Value(); } else { - CHECK(args[2]->IsInt32() && args[2].As()->Value() == -1); + CHECK(args[2]->IsInt32() && args[2].As()->Value() == -1); auth_tag_len = kNoAuthTagLength; } @@ -2799,9 +2801,9 @@ void CipherBase::InitIv(const FunctionCallbackInfo& args) { // represent a valid length at this point. unsigned int auth_tag_len; if (args[3]->IsUint32()) { - auth_tag_len = args[3].As()->Value(); + auth_tag_len = args[3].As()->Value(); } else { - CHECK(args[3]->IsInt32() && args[3].As()->Value() == -1); + CHECK(args[3]->IsInt32() && args[3].As()->Value() == -1); auth_tag_len = kNoAuthTagLength; } @@ -3002,7 +3004,7 @@ void CipherBase::SetAAD(const FunctionCallbackInfo& args) { CHECK_EQ(args.Length(), 2); CHECK(args[1]->IsInt32()); - int plaintext_len = args[1].As()->Value(); + int plaintext_len = args[1].As()->Value(); if (!cipher->SetAAD(Buffer::Data(args[0]), Buffer::Length(args[0]), plaintext_len)) From b30aeee82d174db64b453eb4ab61bfc756b2d794 Mon Sep 17 00:00:00 2001 From: Ajido Date: Wed, 25 Apr 2018 23:46:54 +0900 Subject: [PATCH 13/76] doc: add emitter.off() to events.md PR-URL: https://github.com/nodejs/node/pull/20291 Refs: https://github.com/nodejs/node/pull/17156 Reviewed-By: Colin Ihrig Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Vse Mozhet Byt Reviewed-By: Anna Henningsen --- doc/api/events.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/api/events.md b/doc/api/events.md index a5a45ca3de4834..35ad9eaed393b9 100644 --- a/doc/api/events.md +++ b/doc/api/events.md @@ -372,6 +372,17 @@ console.log(util.inspect(server.listeners('connection'))); // Prints: [ [Function] ] ``` +### emitter.off(eventName, listener) + + +* `eventName` {string|symbol} +* `listener` {Function} +* Returns: {EventEmitter} + +Alias for [`emitter.removeListener()`][]. + ### emitter.on(eventName, listener) +* `type` {integer} The frame type. +* `code` {integer} The error code. +* `id` {integer} The stream id (or `0` if the frame isn't associated with a + stream). + The `'frameError'` event is emitted when an error occurs while attempting to send a frame on the session. If the frame that could not be sent is associated with a specific `Http2Stream`, an attempt to emit `'frameError'` event on the `Http2Stream` is made. -When invoked, the handler function will receive three arguments: - -* An integer identifying the frame type. -* An integer identifying the error code. -* An integer identifying the stream (or 0 if the frame is not associated with - a stream). - If the `'frameError'` event is associated with a stream, the stream will be closed and destroyed immediately following the `'frameError'` event. If the event is not associated with a stream, the `Http2Session` will be shut down From 2e43a788d99fd4a1f6b39e122c7b0b48ce89c2d1 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 08:45:35 +0200 Subject: [PATCH 15/76] crypto: simplify diffiehellman getFormat function MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit aims to simplify the getFormat function in diffiehellman.js. PR-URL: https://github.com/nodejs/node/pull/20246 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- lib/internal/crypto/diffiehellman.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index 329add6d4d7cd5..dad7a903b26a5e 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -219,21 +219,15 @@ function encode(buffer, encoding) { } function getFormat(format) { - let f; if (format) { if (format === 'compressed') - f = POINT_CONVERSION_COMPRESSED; - else if (format === 'hybrid') - f = POINT_CONVERSION_HYBRID; - // Default - else if (format === 'uncompressed') - f = POINT_CONVERSION_UNCOMPRESSED; - else + return POINT_CONVERSION_COMPRESSED; + if (format === 'hybrid') + return POINT_CONVERSION_HYBRID; + if (format !== 'uncompressed') throw new ERR_CRYPTO_ECDH_INVALID_FORMAT(format); - } else { - f = POINT_CONVERSION_UNCOMPRESSED; } - return f; + return POINT_CONVERSION_UNCOMPRESSED; } module.exports = { From 1568ed8f28422030ee96be4915e9bcdad5ef919b Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 10:47:24 +0200 Subject: [PATCH 16/76] crypto: add getIntOption function to reduce dupl MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a getIntOption function to reduce the code duplicated for getting the padding, and saltLength options. PR-URL: https://github.com/nodejs/node/pull/20247 Reviewed-By: Anna Henningsen Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- lib/internal/crypto/sig.js | 55 ++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 32 deletions(-) diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index aed679e99b9b8f..92b42412a82e92 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -53,6 +53,25 @@ Sign.prototype.update = function update(data, encoding) { return this; }; +function getPadding(options) { + return getIntOption('padding', RSA_PKCS1_PADDING, options); +} + +function getSaltLength(options) { + return getIntOption('saltLength', RSA_PSS_SALTLEN_AUTO, options); +} + +function getIntOption(name, defaultValue, options) { + if (options.hasOwnProperty(name)) { + if (options[name] === options[name] >> 0) { + return options[name]; + } else { + throw new ERR_INVALID_OPT_VALUE(name, options[name]); + } + } + return defaultValue; +} + Sign.prototype.sign = function sign(options, encoding) { if (!options) throw new ERR_CRYPTO_SIGN_KEY_REQUIRED(); @@ -61,23 +80,9 @@ Sign.prototype.sign = function sign(options, encoding) { var passphrase = options.passphrase || null; // Options specific to RSA - var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { - if (options.padding === options.padding >> 0) { - rsaPadding = options.padding; - } else { - throw new ERR_INVALID_OPT_VALUE('padding', options.padding); - } - } + var rsaPadding = getPadding(options); - var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { - if (options.saltLength === options.saltLength >> 0) { - pssSaltLength = options.saltLength; - } else { - throw new ERR_INVALID_OPT_VALUE('saltLength', options.saltLength); - } - } + var pssSaltLength = getSaltLength(options); key = toBuf(key); if (!isArrayBufferView(key)) { @@ -119,23 +124,9 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { sigEncoding = sigEncoding || getDefaultEncoding(); // Options specific to RSA - var rsaPadding = RSA_PKCS1_PADDING; - if (options.hasOwnProperty('padding')) { - if (options.padding === options.padding >> 0) { - rsaPadding = options.padding; - } else { - throw new ERR_INVALID_OPT_VALUE('padding', options.padding); - } - } + var rsaPadding = getPadding(options); - var pssSaltLength = RSA_PSS_SALTLEN_AUTO; - if (options.hasOwnProperty('saltLength')) { - if (options.saltLength === options.saltLength >> 0) { - pssSaltLength = options.saltLength; - } else { - throw new ERR_INVALID_OPT_VALUE('saltLength', options.saltLength); - } - } + var pssSaltLength = getSaltLength(options); key = toBuf(key); if (!isArrayBufferView(key)) { From 8c8aa5f1700d122a4a8be5609eab8b0eab1c2a8e Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Tue, 24 Apr 2018 13:42:44 +0200 Subject: [PATCH 17/76] crypto: add checkIsArrayBufferView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a checkIsArrayBufferView function to avoid some code duplication in sig.js PR-URL: https://github.com/nodejs/node/pull/20251 Reviewed-By: Ben Noordhuis Reviewed-By: Joyee Cheung Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- lib/internal/crypto/sig.js | 39 ++++++------------------------------- lib/internal/crypto/util.js | 12 ++++++++++++ 2 files changed, 18 insertions(+), 33 deletions(-) diff --git a/lib/internal/crypto/sig.js b/lib/internal/crypto/sig.js index 92b42412a82e92..1073b83d720098 100644 --- a/lib/internal/crypto/sig.js +++ b/lib/internal/crypto/sig.js @@ -14,10 +14,10 @@ const { RSA_PKCS1_PADDING } = process.binding('constants').crypto; const { + checkIsArrayBufferView, getDefaultEncoding, toBuf } = require('internal/crypto/util'); -const { isArrayBufferView } = require('internal/util/types'); const { Writable } = require('stream'); const { inherits } = require('util'); @@ -41,14 +41,7 @@ Sign.prototype._write = function _write(chunk, encoding, callback) { Sign.prototype.update = function update(data, encoding) { encoding = encoding || getDefaultEncoding(); - data = toBuf(data, encoding); - if (!isArrayBufferView(data)) { - throw new ERR_INVALID_ARG_TYPE( - 'data', - ['string', 'Buffer', 'TypedArray', 'DataView'], - data - ); - } + data = checkIsArrayBufferView('data', toBuf(data, encoding)); this._handle.update(data); return this; }; @@ -84,14 +77,7 @@ Sign.prototype.sign = function sign(options, encoding) { var pssSaltLength = getSaltLength(options); - key = toBuf(key); - if (!isArrayBufferView(key)) { - throw new ERR_INVALID_ARG_TYPE( - 'key', - ['string', 'Buffer', 'TypedArray', 'DataView'], - key - ); - } + key = checkIsArrayBufferView('key', toBuf(key)); var ret = this._handle.sign(key, passphrase, rsaPadding, pssSaltLength); @@ -128,23 +114,10 @@ Verify.prototype.verify = function verify(options, signature, sigEncoding) { var pssSaltLength = getSaltLength(options); - key = toBuf(key); - if (!isArrayBufferView(key)) { - throw new ERR_INVALID_ARG_TYPE( - 'key', - ['string', 'Buffer', 'TypedArray', 'DataView'], - key - ); - } + key = checkIsArrayBufferView('key', toBuf(key)); - signature = toBuf(signature, sigEncoding); - if (!isArrayBufferView(signature)) { - throw new ERR_INVALID_ARG_TYPE( - 'signature', - ['string', 'Buffer', 'TypedArray', 'DataView'], - signature - ); - } + signature = checkIsArrayBufferView('signature', + toBuf(signature, sigEncoding)); return this._handle.verify(key, signature, rsaPadding, pssSaltLength); }; diff --git a/lib/internal/crypto/util.js b/lib/internal/crypto/util.js index 095ca0478bd99f..59a5d57a1e4f39 100644 --- a/lib/internal/crypto/util.js +++ b/lib/internal/crypto/util.js @@ -83,7 +83,19 @@ function timingSafeEqual(buf1, buf2) { return _timingSafeEqual(buf1, buf2); } +function checkIsArrayBufferView(name, buffer) { + if (!isArrayBufferView(buffer)) { + throw new ERR_INVALID_ARG_TYPE( + name, + ['string', 'Buffer', 'TypedArray', 'DataView'], + buffer + ); + } + return buffer; +} + module.exports = { + checkIsArrayBufferView, getCiphers, getCurves, getDefaultEncoding, From 71040a81ce835c20110b6332d271de54eb551d20 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Wed, 25 Apr 2018 09:11:37 +0200 Subject: [PATCH 18/76] crypto: make pbkdf2 use checkIsArrayBufferView MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates pbkdf2 to use checkIsArrayBufferView from internal/crypto/util. PR-URL: https://github.com/nodejs/node/pull/20251 Reviewed-By: Ben Noordhuis Reviewed-By: Joyee Cheung Reviewed-By: Tobias Nießen Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- lib/internal/crypto/pbkdf2.js | 17 +++-------------- test/parallel/test-crypto-pbkdf2.js | 3 ++- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/lib/internal/crypto/pbkdf2.js b/lib/internal/crypto/pbkdf2.js index 4a7f26b509b521..82ea9feb852649 100644 --- a/lib/internal/crypto/pbkdf2.js +++ b/lib/internal/crypto/pbkdf2.js @@ -7,10 +7,10 @@ const { ERR_OUT_OF_RANGE } = require('internal/errors').codes; const { + checkIsArrayBufferView, getDefaultEncoding, toBuf } = require('internal/crypto/util'); -const { isArrayBufferView } = require('internal/util/types'); const { PBKDF2 } = process.binding('crypto'); @@ -39,19 +39,8 @@ function _pbkdf2(password, salt, iterations, keylen, digest, callback) { if (digest !== null && typeof digest !== 'string') throw new ERR_INVALID_ARG_TYPE('digest', ['string', 'null'], digest); - password = toBuf(password); - salt = toBuf(salt); - - if (!isArrayBufferView(password)) { - throw new ERR_INVALID_ARG_TYPE('password', - ['string', 'Buffer', 'TypedArray'], - password); - } - - if (!isArrayBufferView(salt)) { - throw new ERR_INVALID_ARG_TYPE('salt', - ['string', 'Buffer', 'TypedArray'], salt); - } + password = checkIsArrayBufferView('password', toBuf(password)); + salt = checkIsArrayBufferView('salt', toBuf(salt)); if (typeof iterations !== 'number') throw new ERR_INVALID_ARG_TYPE('iterations', 'number', iterations); diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index b4ecd3c6061158..f65176132ae5c4 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -123,7 +123,8 @@ assert.throws( }); [1, {}, [], true, undefined, null].forEach((input) => { - const msgPart2 = `Buffer, or TypedArray. Received type ${typeof input}`; + const msgPart2 = 'Buffer, TypedArray, or DataView.' + + ` Received type ${typeof input}`; assert.throws( () => crypto.pbkdf2(input, 'salt', 8, 8, 'sha256', common.mustNotCall()), { From 8847d45c5282b649b564c67ec355b5f5d1ada72d Mon Sep 17 00:00:00 2001 From: Santiago Gimeno Date: Sun, 22 Apr 2018 22:22:25 +0200 Subject: [PATCH 19/76] test: fix flaky child-process-exec-kill-throws Kill the child process with `SIGKILL` to make sure the child process does not remain alive. Fixes: https://github.com/nodejs/node/issues/20139 PR-URL: https://github.com/nodejs/node/pull/20213 Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca Reviewed-By: Trivikram Kamat Reviewed-By: Weijia Wang Reviewed-By: James M Snell --- test/parallel/test-child-process-exec-kill-throws.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/test/parallel/test-child-process-exec-kill-throws.js b/test/parallel/test-child-process-exec-kill-throws.js index 35e5ff8b7bce0f..d6a0d4da19eae7 100644 --- a/test/parallel/test-child-process-exec-kill-throws.js +++ b/test/parallel/test-child-process-exec-kill-throws.js @@ -19,7 +19,8 @@ if (process.argv[2] === 'child') { }; const cmd = `"${process.execPath}" "${__filename}" child`; - const options = { maxBuffer: 0 }; + const options = { maxBuffer: 0, killSignal: 'SIGKILL' }; + const child = cp.exec(cmd, options, common.mustCall((err, stdout, stderr) => { // Verify that if ChildProcess#kill() throws, the error is reported. assert.strictEqual(err.message, 'mock error', err); From 4d660b3190d8ccd8fb9f6f3d82b8fefbc98700ca Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 11:49:37 -0400 Subject: [PATCH 20/76] n-api,test: make method static One non-static method remains PR-URL: https://github.com/nodejs/node/pull/20292 Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat --- test/addons-napi/test_reference/test_reference.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/addons-napi/test_reference/test_reference.c b/test/addons-napi/test_reference/test_reference.c index 641b1cb82ba8e1..75abc49ad3280e 100644 --- a/test/addons-napi/test_reference/test_reference.c +++ b/test/addons-napi/test_reference/test_reference.c @@ -11,7 +11,7 @@ static napi_value GetFinalizeCount(napi_env env, napi_callback_info info) { return result; } -void FinalizeExternal(napi_env env, void* data, void* hint) { +static void FinalizeExternal(napi_env env, void* data, void* hint) { int *actual_value = data; NAPI_ASSERT_RETURN_VOID(env, actual_value == &test_value, "The correct pointer was passed to the finalizer"); From 40a9fc1ea28155002b1380367d0a8359e5ac0852 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 13:49:48 -0400 Subject: [PATCH 21/76] n-api: update cli documentation Fixes: https://github.com/nodejs/node/issues/20082 PR-URL: https://github.com/nodejs/node/pull/20301 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig Reviewed-By: Richard Lau Reviewed-By: Vse Mozhet Byt Reviewed-By: Trivikram Kamat --- doc/api/cli.md | 3 +-- doc/node.1 | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/doc/api/cli.md b/doc/api/cli.md index 164e370fff5e15..5de5f0ff6fafd1 100644 --- a/doc/api/cli.md +++ b/doc/api/cli.md @@ -144,8 +144,7 @@ tcp port and communicate using the [Chrome DevTools Protocol][]. added: v7.10.0 --> -Enable loading native modules compiled with the ABI-stable Node.js API (N-API) -(experimental). +This option is a no-op. It is kept for compatibility. ### `--no-deprecation` diff --git a/doc/node.1 b/doc/node.1 index 24d8260b8765ac..c3572acee7bf6b 100644 --- a/doc/node.1 +++ b/doc/node.1 @@ -122,8 +122,7 @@ V8 Inspector integration allows attaching Chrome DevTools and IDEs to Node.js in It uses the Chrome DevTools Protocol. . .It Fl -napi-modules -Enable loading native modules compiled with the ABI-stable Node.js API (N-API) -(experimental). +This option is a no-op. It is kept for compatibility. . .It Fl -no-deprecation Silence deprecation warnings. From 949a7b650092aa8ec0aa22717319fac0dea0cd50 Mon Sep 17 00:00:00 2001 From: Gabriel Schulhof Date: Wed, 25 Apr 2018 13:15:50 -0400 Subject: [PATCH 22/76] n-api,test: remove superfluous persistent Remove a superfluos persistent from test_constructor_name.c. PR-URL: https://github.com/nodejs/node/pull/20299 Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- test/addons-napi/test_constructor/test_constructor_name.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/test/addons-napi/test_constructor/test_constructor_name.c b/test/addons-napi/test_constructor/test_constructor_name.c index b30ea4333747d3..e12deb80d23af8 100644 --- a/test/addons-napi/test_constructor/test_constructor_name.c +++ b/test/addons-napi/test_constructor/test_constructor_name.c @@ -1,8 +1,6 @@ #include #include "../common.h" -napi_ref constructor_; - static napi_value New(napi_env env, napi_callback_info info) { napi_value _this; NAPI_CALL(env, napi_get_cb_info(env, info, NULL, NULL, &_this, NULL)); @@ -14,9 +12,6 @@ static napi_value Init(napi_env env, napi_value exports) { napi_value cons; NAPI_CALL(env, napi_define_class( env, "MyObject_Extra", 8, New, NULL, 0, NULL, &cons)); - - NAPI_CALL(env, - napi_create_reference(env, cons, 1, &constructor_)); return cons; } From 40b7351dbc768a2f98934fb7802c3b0a08175815 Mon Sep 17 00:00:00 2001 From: Eugene Ostroukhov Date: Tue, 24 Apr 2018 11:16:55 -0700 Subject: [PATCH 23/76] inspector: Use default uv_listen backlog size PR-URL: https://github.com/nodejs/node/pull/20254 Reviewed-By: Rich Trott Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ben Noordhuis Reviewed-By: Ali Ijaz Sheikh Reviewed-By: Trivikram Kamat --- src/inspector_socket_server.cc | 3 +- test/parallel/test-inspector-stress-http.js | 34 +++++++++++++++++++++ 2 files changed, 36 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-inspector-stress-http.js diff --git a/src/inspector_socket_server.cc b/src/inspector_socket_server.cc index 3725c19e93fb86..e69c8d768be156 100644 --- a/src/inspector_socket_server.cc +++ b/src/inspector_socket_server.cc @@ -587,7 +587,8 @@ int ServerSocket::Listen(InspectorSocketServer* inspector_server, CHECK_EQ(0, uv_tcp_init(loop, server)); int err = uv_tcp_bind(server, addr, 0); if (err == 0) { - err = uv_listen(reinterpret_cast(server), 1, + // 511 is the value used by a 'net' module by default + err = uv_listen(reinterpret_cast(server), 511, ServerSocket::SocketConnectedCallback); } if (err == 0) { diff --git a/test/parallel/test-inspector-stress-http.js b/test/parallel/test-inspector-stress-http.js new file mode 100644 index 00000000000000..4787c35e32c899 --- /dev/null +++ b/test/parallel/test-inspector-stress-http.js @@ -0,0 +1,34 @@ +// Flags: --expose-internals +'use strict'; +const common = require('../common'); + +common.skipIfInspectorDisabled(); + +const assert = require('assert'); +const { NodeInstance } = require('../common/inspector-helper.js'); + +async function testHttp(child, number) { + try { + await child.httpGet(null, '/json/list'); + return true; + } catch (e) { + console.error(`Attempt ${number} failed`, e); + return false; + } +} + +async function runTest() { + const child = new NodeInstance(undefined, ''); + + const promises = []; + for (let i = 0; i < 100; i++) { + promises.push(testHttp(child, i)); + } + const result = await Promise.all(promises); + assert(!result.some((a) => !a), 'Some attempts failed'); + return child.kill(); +} + +common.crashOnUnhandledRejection(); + +runTest(); From c87e9fdf7e78d36b1cb724eac08a5ab69bb244c6 Mon Sep 17 00:00:00 2001 From: Robert Nagy Date: Tue, 17 Apr 2018 11:37:50 +0200 Subject: [PATCH 24/76] http: added aborted property to request PR-URL: https://github.com/nodejs/node/pull/20094 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca --- doc/api/http.md | 12 +++++++++- doc/api/http2.md | 10 ++++++++ lib/_http_client.js | 6 ++++- lib/_http_incoming.js | 2 ++ lib/_http_server.js | 1 + lib/internal/http2/compat.js | 7 ++++++ test/parallel/test-http-aborted.js | 26 +++++++++++++++++++++ test/parallel/test-http2-compat-aborted.js | 27 ++++++++++++++++++++++ 8 files changed, 89 insertions(+), 2 deletions(-) create mode 100644 test/parallel/test-http-aborted.js create mode 100644 test/parallel/test-http2-compat-aborted.js diff --git a/doc/api/http.md b/doc/api/http.md index d6f738cb81ff54..d3e495ea3df5a3 100644 --- a/doc/api/http.md +++ b/doc/api/http.md @@ -1483,7 +1483,7 @@ following additional events, methods, and properties. added: v0.3.8 --> -Emitted when the request has been aborted and the network socket has closed. +Emitted when the request has been aborted. ### Event: 'close' + +* {boolean} + +The `message.aborted` property will be `true` if the request has +been aborted. + ### message.destroy([error]) + +* {boolean} + +The `request.aborted` property will be `true` if the request has +been aborted. + #### request.destroy([error]) * Returns: {integer} The `os.uptime()` method returns the system uptime in number of seconds. -On Windows the returned value includes fractions of a second. Use `Math.floor()` -to get whole seconds. - ## os.userInfo([options]) > Stability: 0 - Deprecated: Use [`crypto.createCipheriv()`][] instead. @@ -1336,7 +1341,9 @@ Creates and returns a `Cipher` object that uses the given `algorithm` and The `options` argument controls stream behavior and is optional except when a cipher in CCM mode is used (e.g. `'aes-128-ccm'`). In that case, the `authTagLength` option is required and specifies the length of the -authentication tag in bytes, see [CCM mode][]. +authentication tag in bytes, see [CCM mode][]. In GCM mode, the `authTagLength` +option is not required but can be used to set the length of the authentication +tag that will be returned by `getAuthTag()` and defaults to 16 bytes. The `algorithm` is dependent on OpenSSL, examples are `'aes192'`, etc. On recent OpenSSL releases, `openssl list-cipher-algorithms` will display the @@ -1366,6 +1373,10 @@ Adversaries][] for details. -* `array` {Array|Object} -* `columns` {string[]} Display only selected properties of objects in the - `array`. - -This method does not display anything unless used in the inspector. Prints to -`stdout` the array `array` formatted as a table. - ### console.timeStamp([label]) -The `'goaway'` event is emitted when a `GOAWAY` frame is received. When invoked, -the handler function will receive three arguments: - * `errorCode` {number} The HTTP/2 error code specified in the `GOAWAY` frame. * `lastStreamID` {number} The ID of the last stream the remote peer successfully processed (or `0` if no ID is specified). * `opaqueData` {Buffer} If additional opaque data was included in the `GOAWAY` frame, a `Buffer` instance will be passed containing that data. +The `'goaway'` event is emitted when a `GOAWAY` frame is received. + The `Http2Session` instance will be shut down automatically when the `'goaway'` event is emitted. From 27ac6d9b7f29869f52fdfdab633f0bd5e99388e9 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Wed, 25 Apr 2018 17:51:32 +0200 Subject: [PATCH 46/76] tools: add log output to crashes PR-URL: https://github.com/nodejs/node/pull/20295 Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Matheus Marchini Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Refael Ackermann --- tools/test.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/tools/test.py b/tools/test.py index e652e47092c55b..a0a3121e486b3e 100755 --- a/tools/test.py +++ b/tools/test.py @@ -298,10 +298,8 @@ def HasRun(self, output): if output.HasCrashed(): self.severity = 'crashed' - exit_code = output.output.exit_code - self.traceback = "oh no!\nexit code: " + PrintCrashed(exit_code) - if output.HasTimedOut(): + elif output.HasTimedOut(): self.severity = 'fail' else: From afbdd14819b087996b1481d43e31c19c31a052f1 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Wed, 25 Apr 2018 23:44:38 +0300 Subject: [PATCH 47/76] tools: simplify HTML generation PR-URL: https://github.com/nodejs/node/pull/20307 Reviewed-By: Anna Henningsen Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- Makefile | 2 +- test/doctool/test-doctool-html.js | 2 - tools/doc/generate.js | 5 +- tools/doc/html.js | 85 ++++++++----------------------- 4 files changed, 24 insertions(+), 70 deletions(-) diff --git a/Makefile b/Makefile index 6736d601685dce..b3e65cec6030a9 100644 --- a/Makefile +++ b/Makefile @@ -652,7 +652,7 @@ tools/doc/node_modules/js-yaml/package.json: gen-json = tools/doc/generate.js --format=json $< > $@ gen-html = tools/doc/generate.js --node-version=$(FULLVERSION) --format=html \ - --template=doc/template.html --analytics=$(DOCS_ANALYTICS) $< > $@ + --analytics=$(DOCS_ANALYTICS) $< > $@ out/doc/api/%.json: doc/api/%.md $(call available-node, $(gen-json)) diff --git a/test/doctool/test-doctool-html.js b/test/doctool/test-doctool-html.js index bd1c5ddecac321..91037bfd6501bc 100644 --- a/test/doctool/test-doctool-html.js +++ b/test/doctool/test-doctool-html.js @@ -10,7 +10,6 @@ try { const assert = require('assert'); const fs = require('fs'); -const path = require('path'); const fixtures = require('../common/fixtures'); const processIncludes = require('../../tools/doc/preprocess.js'); const html = require('../../tools/doc/html.js'); @@ -107,7 +106,6 @@ testData.forEach((item) => { { input: preprocessed, filename: 'foo', - template: path.resolve(__dirname, '../../doc/template.html'), nodeVersion: process.version, analytics: item.analyticsId, }, diff --git a/tools/doc/generate.js b/tools/doc/generate.js index 0da9dba4e6558f..9f217b19c7225f 100644 --- a/tools/doc/generate.js +++ b/tools/doc/generate.js @@ -29,7 +29,6 @@ const fs = require('fs'); const args = process.argv.slice(2); let format = 'json'; -let template = null; let filename = null; let nodeVersion = null; let analytics = null; @@ -39,8 +38,6 @@ args.forEach(function(arg) { filename = arg; } else if (arg.startsWith('--format=')) { format = arg.replace(/^--format=/, ''); - } else if (arg.startsWith('--template=')) { - template = arg.replace(/^--template=/, ''); } else if (arg.startsWith('--node-version=')) { nodeVersion = arg.replace(/^--node-version=/, ''); } else if (arg.startsWith('--analytics=')) { @@ -71,7 +68,7 @@ function next(er, input) { break; case 'html': - require('./html')({ input, filename, template, nodeVersion, analytics }, + require('./html')({ input, filename, nodeVersion, analytics }, (err, html) => { if (err) throw err; console.log(html); diff --git a/tools/doc/html.js b/tools/doc/html.js index ff0230309ee99a..439fc057012ca7 100644 --- a/tools/doc/html.js +++ b/tools/doc/html.js @@ -25,7 +25,6 @@ const common = require('./common.js'); const fs = require('fs'); const marked = require('marked'); const path = require('path'); -const preprocess = require('./preprocess.js'); const typeParser = require('./type-parser.js'); module.exports = toHTML; @@ -42,76 +41,36 @@ marked.setOptions({ renderer: renderer }); -// TODO(chrisdickinson): never stop vomiting / fix this. -const gtocPath = path.resolve(path.join( - __dirname, - '..', - '..', - 'doc', - 'api', - '_toc.md' -)); -var gtocLoading = null; -var gtocData = null; +const docPath = path.resolve(__dirname, '..', '..', 'doc'); + +const gtocPath = path.join(docPath, 'api', '_toc.md'); +const gtocMD = fs.readFileSync(gtocPath, 'utf8').replace(/^@\/\/.*$/gm, ''); +const gtocHTML = marked(gtocMD).replace( + / ` Date: Wed, 25 Apr 2018 14:05:39 -0500 Subject: [PATCH 48/76] doc: remove eu-strip from tarball This is been removed because of this: the source is not provided it adds 105ko of useless files It's only used in the android and fuchsia GN builds Fixes: #20280 PR-URL: https://github.com/nodejs/node/pull/20304 Fixes: https://github.com/nodejs/node/issues/20280 Reviewed-By: Ben Noordhuis Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Colin Ihrig Reviewed-By: Ruben Bridgewater Reviewed-By: Matheus Marchini Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- .gitignore | 1 + deps/v8/third_party/eu-strip/README.v8 | 24 ---------------------- deps/v8/third_party/eu-strip/bin/eu-strip | Bin 105120 -> 0 bytes 3 files changed, 1 insertion(+), 24 deletions(-) delete mode 100644 deps/v8/third_party/eu-strip/README.v8 delete mode 100755 deps/v8/third_party/eu-strip/bin/eu-strip diff --git a/.gitignore b/.gitignore index 7be817acce2349..ebeedeac6b8fe0 100644 --- a/.gitignore +++ b/.gitignore @@ -127,3 +127,4 @@ deps/v8/src/Debug/ deps/v8/src/Release/ deps/v8/src/inspector/Debug/ deps/v8/src/inspector/Release/ +deps/v8/third_party/eu-strip/ diff --git a/deps/v8/third_party/eu-strip/README.v8 b/deps/v8/third_party/eu-strip/README.v8 deleted file mode 100644 index e84974d92b9cec..00000000000000 --- a/deps/v8/third_party/eu-strip/README.v8 +++ /dev/null @@ -1,24 +0,0 @@ -Name: eu-strip -URL: https://sourceware.org/elfutils/ -Version: 0.158 -Security Critical: no -License: LGPL 3 -License File: NOT_SHIPPED - -Description: - -Patched eu-strip from elfutils. - -Build instructions (on Trusty; note that this will build the -Ubuntu-patched version of elfutils): -$ mkdir elfutils -$ cd elfutils -$ apt-get source elfutils -$ cd elfutils-0.158 -[ Edit libelf/elf_end.c and remove the free() on line 164. ] -$ ./configure -$ make -$ gcc -std=gnu99 -Wall -Wshadow -Wunused -Wextra -fgnu89-inline - -Wformat=2 -Werror -g -O2 -Wl,-rpath-link,libelf:libdw -o eu-strip - src/strip.o libebl/libebl.a libelf/libelf.a lib/libeu.a -ldl -$ eu-strip ./eu-strip # Keep the binary small, please. diff --git a/deps/v8/third_party/eu-strip/bin/eu-strip b/deps/v8/third_party/eu-strip/bin/eu-strip deleted file mode 100755 index 994e2263b9185f77169c6c8545869d3c84cf0a8a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 105120 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 qqL|@9Ud( Date: Thu, 26 Apr 2018 02:28:08 +0300 Subject: [PATCH 49/76] tools: remove redundant RegExp flag PR-URL: https://github.com/nodejs/node/pull/20309 Reviewed-By: Ruben Bridgewater Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- tools/doc/preprocess.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/doc/preprocess.js b/tools/doc/preprocess.js index f8d394735dd30b..554af2ccb77ae0 100644 --- a/tools/doc/preprocess.js +++ b/tools/doc/preprocess.js @@ -6,7 +6,7 @@ const path = require('path'); const fs = require('fs'); const includeExpr = /^@include\s+([\w-]+)(?:\.md)?$/gmi; -const commentExpr = /^@\/\/.*$/gmi; +const commentExpr = /^@\/\/.*$/gm; function processIncludes(inputFile, input, cb) { const includes = input.match(includeExpr); From f3b858dbe37917f7376d916981b7835cb4edd54b Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Thu, 26 Apr 2018 02:49:11 +0300 Subject: [PATCH 50/76] doc: unify and dedupe returned values in timers.md PR-URL: https://github.com/nodejs/node/pull/20310 Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell Reviewed-By: Tiancheng "Timothy" Gu --- doc/api/timers.md | 25 ++++++++----------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/doc/api/timers.md b/doc/api/timers.md index 0cc535352a0697..e3e995004781f0 100644 --- a/doc/api/timers.md +++ b/doc/api/timers.md @@ -28,7 +28,7 @@ functions that can be used to control this default behavior. added: v9.7.0 --> -* Returns: {Immediate} +* Returns: {Immediate} a reference to `immediate` When called, requests that the Node.js event loop *not* exit so long as the `Immediate` is active. Calling `immediate.ref()` multiple times will have no @@ -37,22 +37,18 @@ effect. By default, all `Immediate` objects are "ref'ed", making it normally unnecessary to call `immediate.ref()` unless `immediate.unref()` had been called previously. -Returns a reference to the `Immediate`. - ### immediate.unref() -* Returns: {Immediate} +* Returns: {Immediate} a reference to `immediate` When called, the active `Immediate` object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, the process may exit before the `Immediate` object's callback is invoked. Calling `immediate.unref()` multiple times will have no effect. -Returns a reference to the `Immediate`. - ## Class: Timeout This object is created internally and is returned from [`setTimeout()`][] and @@ -70,7 +66,7 @@ control this default behavior. added: v0.9.1 --> -* Returns: {Timeout} +* Returns: {Timeout} a reference to `timeout` When called, requests that the Node.js event loop *not* exit so long as the `Timeout` is active. Calling `timeout.ref()` multiple times will have no effect. @@ -78,14 +74,12 @@ When called, requests that the Node.js event loop *not* exit so long as the By default, all `Timeout` objects are "ref'ed", making it normally unnecessary to call `timeout.ref()` unless `timeout.unref()` had been called previously. -Returns a reference to the `Timeout`. - ### timeout.unref() -* Returns: {Timeout} +* Returns: {Timeout} a reference to `timeout` When called, the active `Timeout` object will not require the Node.js event loop to remain active. If there is no other activity keeping the event loop running, @@ -96,8 +90,6 @@ Calling `timeout.unref()` creates an internal timer that will wake the Node.js event loop. Creating too many of these can adversely impact performance of the Node.js application. -Returns a reference to the `Timeout`. - ## Scheduling Timers A timer in Node.js is an internal construct that calls a given function after @@ -113,9 +105,10 @@ added: v0.9.1 * `callback` {Function} The function to call at the end of this turn of [the Node.js Event Loop] * `...args` {any} Optional arguments to pass when the `callback` is called. +* Returns: {Immediate} for use with [`clearImmediate()`][] Schedules the "immediate" execution of the `callback` after I/O events' -callbacks. Returns an `Immediate` for use with [`clearImmediate()`][]. +callbacks. When multiple calls to `setImmediate()` are made, the `callback` functions are queued for execution in the order in which they are created. The entire callback @@ -155,10 +148,9 @@ added: v0.0.1 * `delay` {number} The number of milliseconds to wait before calling the `callback`. * `...args` {any} Optional arguments to pass when the `callback` is called. -* Returns: {Timeout} +* Returns: {Timeout} for use with [`clearInterval()`][] Schedules repeated execution of `callback` every `delay` milliseconds. -Returns a `Timeout` for use with [`clearInterval()`][]. When `delay` is larger than `2147483647` or less than `1`, the `delay` will be set to `1`. @@ -174,10 +166,9 @@ added: v0.0.1 * `delay` {number} The number of milliseconds to wait before calling the `callback`. * `...args` {any} Optional arguments to pass when the `callback` is called. -* Returns: {Timeout} +* Returns: {Timeout} for use with [`clearTimeout()`][] Schedules execution of a one-time `callback` after `delay` milliseconds. -Returns a `Timeout` for use with [`clearTimeout()`][]. The `callback` will likely not be invoked in precisely `delay` milliseconds. Node.js makes no guarantees about the exact timing of when callbacks will fire, From 7e0d507beed5aeb17e29ee5f082bb2596e6116fa Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 25 Apr 2018 22:47:56 -0700 Subject: [PATCH 51/76] console: fix console.table() display edge case If the properties are not specified in `console.table()`, then we should make a best effort to determine them rather than put all values into a "Values" column. PR-URL: https://github.com/nodejs/node/pull/20323 Reviewed-By: Gus Caplan Reviewed-By: Trivikram Kamat Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- lib/console.js | 4 +--- test/parallel/test-console-table.js | 31 +++++++++++++++++++---------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/lib/console.js b/lib/console.js index 39bcf701bf83eb..a0158ec6643782 100644 --- a/lib/console.js +++ b/lib/console.js @@ -363,9 +363,7 @@ Console.prototype.table = function(tabularData, properties) { tabularData = previewSetIterator(tabularData); const setlike = setIter || isSet(tabularData); - if (setlike || - (properties === undefined && - (isArray(tabularData) || isTypedArray(tabularData)))) { + if (setlike) { const values = []; let length = 0; for (const v of tabularData) { diff --git a/test/parallel/test-console-table.js b/test/parallel/test-console-table.js index 39e9099dd717d4..64e2533f175e1d 100644 --- a/test/parallel/test-console-table.js +++ b/test/parallel/test-console-table.js @@ -41,13 +41,13 @@ test([1, 2, 3], ` `); test([Symbol(), 5, [10]], ` -┌─────────┬──────────┐ -│ (index) │ Values │ -├─────────┼──────────┤ -│ 0 │ Symbol() │ -│ 1 │ 5 │ -│ 2 │ [ 10 ] │ -└─────────┴──────────┘ +┌─────────┬────┬──────────┐ +│ (index) │ 0 │ Values │ +├─────────┼────┼──────────┤ +│ 0 │ │ Symbol() │ +│ 1 │ │ 5 │ +│ 2 │ 10 │ │ +└─────────┴────┴──────────┘ `); test([undefined, 5], ` @@ -182,10 +182,10 @@ test({ a: undefined }, ['x'], ` `); test([], ` -┌─────────┬────────┐ -│ (index) │ Values │ -├─────────┼────────┤ -└─────────┴────────┘ +┌─────────┐ +│ (index) │ +├─────────┤ +└─────────┘ `); test(new Map(), ` @@ -194,3 +194,12 @@ test(new Map(), ` ├───────────────────┼─────┼────────┤ └───────────────────┴─────┴────────┘ `); + +test([{ a: 1, b: 'Y' }, { a: 'Z', b: 2 }], ` +┌─────────┬─────┬─────┐ +│ (index) │ a │ b │ +├─────────┼─────┼─────┤ +│ 0 │ 1 │ 'Y' │ +│ 1 │ 'Z' │ 2 │ +└─────────┴─────┴─────┘ +`); From f367090180bde579c3d4ce5c752a5c1df66a6c59 Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Wed, 25 Apr 2018 00:56:35 +0200 Subject: [PATCH 52/76] util: fix isInsideNodeModules inside error MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When isInsideNodeModules gets called while already processing another stack trace, V8 will not call prepareStackTrace again. This used to cause Node.js to just crash — fix it by checking for expected return type of the stack (Array). PR-URL: https://github.com/nodejs/node/pull/20266 Fixes: https://github.com/nodejs/node/issues/20258 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- lib/internal/util.js | 19 ++++++++++--------- ...st-buffer-constructor-deprecation-error.js | 17 +++++++++++++++++ 2 files changed, 27 insertions(+), 9 deletions(-) create mode 100644 test/parallel/test-buffer-constructor-deprecation-error.js diff --git a/lib/internal/util.js b/lib/internal/util.js index ce25317b778a3f..071563a737815b 100644 --- a/lib/internal/util.js +++ b/lib/internal/util.js @@ -356,16 +356,17 @@ function isInsideNodeModules() { // Iterate over all stack frames and look for the first one not coming // from inside Node.js itself: - for (const frame of stack) { - const filename = frame.getFileName(); - // If a filename does not start with / or contain \, - // it's likely from Node.js core. - if (!/^\/|\\/.test(filename)) - continue; - return kNodeModulesRE.test(filename); + if (Array.isArray(stack)) { + for (const frame of stack) { + const filename = frame.getFileName(); + // If a filename does not start with / or contain \, + // it's likely from Node.js core. + if (!/^\/|\\/.test(filename)) + continue; + return kNodeModulesRE.test(filename); + } } - - return false; // This should be unreachable. + return false; } diff --git a/test/parallel/test-buffer-constructor-deprecation-error.js b/test/parallel/test-buffer-constructor-deprecation-error.js new file mode 100644 index 00000000000000..46535e103b33ee --- /dev/null +++ b/test/parallel/test-buffer-constructor-deprecation-error.js @@ -0,0 +1,17 @@ +'use strict'; + +const common = require('../common'); + +const bufferWarning = 'Buffer() is deprecated due to security and usability ' + + 'issues. Please use the Buffer.alloc(), ' + + 'Buffer.allocUnsafe(), or Buffer.from() methods instead.'; + +common.expectWarning('DeprecationWarning', bufferWarning, 'DEP0005'); + +// This is used to make sure that a warning is only emitted once even though +// `new Buffer()` is called twice. +process.on('warning', common.mustCall()); + +Error.prepareStackTrace = (err, trace) => new Buffer(10); + +new Error().stack; From f48db30383ca8b9b62e6b32af5847dd8f2fd7131 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Fri, 27 Apr 2018 15:21:17 +0200 Subject: [PATCH 53/76] src: remove unnecessary copy operations in tracing PR-URL: https://github.com/nodejs/node/pull/20356 Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Anatoli Papirovski --- src/node_trace_events.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/node_trace_events.cc b/src/node_trace_events.cc index 1e02048d1f0843..f37537d54544a2 100644 --- a/src/node_trace_events.cc +++ b/src/node_trace_events.cc @@ -63,7 +63,7 @@ void NodeCategorySet::Enable(const FunctionCallbackInfo& args) { NodeCategorySet* category_set; ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder()); CHECK_NE(category_set, nullptr); - auto categories = category_set->GetCategories(); + const auto& categories = category_set->GetCategories(); if (!category_set->enabled_ && !categories.empty()) { env->tracing_agent()->Enable(categories); category_set->enabled_ = true; @@ -75,7 +75,7 @@ void NodeCategorySet::Disable(const FunctionCallbackInfo& args) { NodeCategorySet* category_set; ASSIGN_OR_RETURN_UNWRAP(&category_set, args.Holder()); CHECK_NE(category_set, nullptr); - auto categories = category_set->GetCategories(); + const auto& categories = category_set->GetCategories(); if (category_set->enabled_ && !categories.empty()) { env->tracing_agent()->Disable(categories); category_set->enabled_ = false; From a0192f2af93f404b65c2fa3fc081a27b5f31b1cf Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 14 Apr 2018 18:26:57 +0200 Subject: [PATCH 54/76] benchmark: add bench for zlib gzip + gunzip cycle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Originally wrote this for some work that is going to take a while longer before it’s ready to be PR’ed, so it seems fine to start with this on its own. PR-URL: https://github.com/nodejs/node/pull/20034 Reviewed-By: James M Snell Reviewed-By: Luigi Pinca Reviewed-By: Ruben Bridgewater --- benchmark/zlib/pipe.js | 39 ++++++++++++++++++++++++++++ test/parallel/test-benchmark-zlib.js | 9 +++++-- 2 files changed, 46 insertions(+), 2 deletions(-) create mode 100644 benchmark/zlib/pipe.js diff --git a/benchmark/zlib/pipe.js b/benchmark/zlib/pipe.js new file mode 100644 index 00000000000000..9b05749bbb824d --- /dev/null +++ b/benchmark/zlib/pipe.js @@ -0,0 +1,39 @@ +'use strict'; +const common = require('../common.js'); +const fs = require('fs'); +const zlib = require('zlib'); + +const bench = common.createBenchmark(main, { + inputLen: [1024], + duration: [5], + type: ['string', 'buffer'] +}); + +function main({ inputLen, duration, type }) { + const buffer = Buffer.alloc(inputLen, fs.readFileSync(__filename)); + const chunk = type === 'buffer' ? buffer : buffer.toString('utf8'); + + const input = zlib.createGzip(); + const output = zlib.createGunzip(); + + let readFromOutput = 0; + input.pipe(output); + if (type === 'string') + output.setEncoding('utf8'); + output.on('data', (chunk) => readFromOutput += chunk.length); + + function write() { + input.write(chunk, write); + } + + bench.start(); + write(); + + setTimeout(() => { + // Give result in GBit/s, like the net benchmarks do + bench.end(readFromOutput * 8 / (1024 ** 3)); + + // Cut off writing the easy way. + input.write = () => {}; + }, duration * 1000); +} diff --git a/test/parallel/test-benchmark-zlib.js b/test/parallel/test-benchmark-zlib.js index 350d05552cda39..25b7d1a4d5f905 100644 --- a/test/parallel/test-benchmark-zlib.js +++ b/test/parallel/test-benchmark-zlib.js @@ -9,5 +9,10 @@ runBenchmark('zlib', 'method=deflate', 'n=1', 'options=true', - 'type=Deflate' - ]); + 'type=Deflate', + 'inputLen=1024', + 'duration=0.001' + ], + { + 'NODEJS_BENCHMARK_ZERO_ALLOWED': 1 + }); From f92dce605759322453f653995f8045c313c5f612 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Fri, 27 Apr 2018 09:39:24 +0200 Subject: [PATCH 55/76] stream: only check options once in Duplex ctor This commit updates the Duplex constructor adding an if statement checking if options is undefined, and removes the check from the following three if statements. PR-URL: https://github.com/nodejs/node/pull/20353 Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell Reviewed-By: Anna Henningsen Reviewed-By: Luigi Pinca --- lib/_stream_duplex.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/lib/_stream_duplex.js b/lib/_stream_duplex.js index b123cdcb4d776f..7059757dbd44b1 100644 --- a/lib/_stream_duplex.js +++ b/lib/_stream_duplex.js @@ -50,17 +50,19 @@ function Duplex(options) { Readable.call(this, options); Writable.call(this, options); + this.allowHalfOpen = true; - if (options && options.readable === false) - this.readable = false; + if (options) { + if (options.readable === false) + this.readable = false; - if (options && options.writable === false) - this.writable = false; + if (options.writable === false) + this.writable = false; - this.allowHalfOpen = true; - if (options && options.allowHalfOpen === false) { - this.allowHalfOpen = false; - this.once('end', onend); + if (options.allowHalfOpen === false) { + this.allowHalfOpen = false; + this.once('end', onend); + } } } From 6b23b1829954e54988223a4394f26a46c2113991 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Thu, 26 Apr 2018 13:22:14 +0200 Subject: [PATCH 56/76] fs: point isFd to isUint32 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit updates the isFd function to call isUint32 instead of doing the same thing. PR-URL: https://github.com/nodejs/node/pull/20330 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tobias Nießen Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Richard Lau Reviewed-By: Joyee Cheung Reviewed-By: Ruben Bridgewater Reviewed-By: James M Snell --- lib/fs.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/fs.js b/lib/fs.js index c49d470f0355dc..50913866f9fdfd 100644 --- a/lib/fs.js +++ b/lib/fs.js @@ -153,9 +153,7 @@ function makeStatsCallback(cb) { }; } -function isFd(path) { - return (path >>> 0) === path; -} +const isFd = isUint32; fs.Stats = Stats; From 8cd94b383e5ccccf18305e9021ef5a4b0da89d75 Mon Sep 17 00:00:00 2001 From: Shigeki Ohtsu Date: Wed, 25 Apr 2018 12:10:26 +0900 Subject: [PATCH 57/76] tls: fix getEphemeralKeyInfo to support X25519 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `EVP_PKEY_EC` only covers ANSI X9.62 curves not IETF ones(curve25519 and curve448). This fixes to add support of X25519 in `tlsSocket.getEphemeralKeyInfo()`. X448 should be added in the future upgrade to OpenSSL-1.1.1. PR-URL: https://github.com/nodejs/node/pull/20273 Fixes: https://github.com/nodejs/node/issues/20262 Reviewed-By: Daniel Bevenius Reviewed-By: Ben Noordhuis Reviewed-By: Tobias Nießen --- src/node_crypto.cc | 21 ++++++++++++++----- src/node_crypto.h | 2 ++ .../test-tls-client-getephemeralkeyinfo.js | 9 ++++++-- 3 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/node_crypto.cc b/src/node_crypto.cc index 42f4d4035d6632..01b6b5c8ea7fb5 100644 --- a/src/node_crypto.cc +++ b/src/node_crypto.cc @@ -2098,7 +2098,8 @@ void SSLWrap::GetEphemeralKeyInfo( EVP_PKEY* key; if (SSL_get_server_tmp_key(w->ssl_, &key)) { - switch (EVP_PKEY_id(key)) { + int kid = EVP_PKEY_id(key); + switch (kid) { case EVP_PKEY_DH: info->Set(context, env->type_string(), FIXED_ONE_BYTE_STRING(env->isolate(), "DH")).FromJust(); @@ -2106,19 +2107,29 @@ void SSLWrap::GetEphemeralKeyInfo( Integer::New(env->isolate(), EVP_PKEY_bits(key))).FromJust(); break; case EVP_PKEY_EC: + // TODO(shigeki) Change this to EVP_PKEY_X25519 and add EVP_PKEY_X448 + // after upgrading to 1.1.1. + case NID_X25519: { - EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key); - int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); - EC_KEY_free(ec); + const char* curve_name; + if (kid == EVP_PKEY_EC) { + EC_KEY* ec = EVP_PKEY_get1_EC_KEY(key); + int nid = EC_GROUP_get_curve_name(EC_KEY_get0_group(ec)); + curve_name = OBJ_nid2sn(nid); + EC_KEY_free(ec); + } else { + curve_name = OBJ_nid2sn(kid); + } info->Set(context, env->type_string(), FIXED_ONE_BYTE_STRING(env->isolate(), "ECDH")).FromJust(); info->Set(context, env->name_string(), OneByteString(args.GetIsolate(), - OBJ_nid2sn(nid))).FromJust(); + curve_name)).FromJust(); info->Set(context, env->size_string(), Integer::New(env->isolate(), EVP_PKEY_bits(key))).FromJust(); } + break; } EVP_PKEY_free(key); } diff --git a/src/node_crypto.h b/src/node_crypto.h index a8fe8b0d4ae7a4..3963f7050f2982 100644 --- a/src/node_crypto.h +++ b/src/node_crypto.h @@ -44,6 +44,8 @@ #endif // !OPENSSL_NO_ENGINE #include #include +// TODO(shigeki) Remove this after upgrading to 1.1.1 +#include #include #include #include diff --git a/test/parallel/test-tls-client-getephemeralkeyinfo.js b/test/parallel/test-tls-client-getephemeralkeyinfo.js index be6777b1ae0049..9432a277ac0fd0 100644 --- a/test/parallel/test-tls-client-getephemeralkeyinfo.js +++ b/test/parallel/test-tls-client-getephemeralkeyinfo.js @@ -82,7 +82,12 @@ function testECDHE256() { } function testECDHE512() { - test(521, 'ECDH', 'secp521r1', null); + test(521, 'ECDH', 'secp521r1', testX25519); + ntests++; +} + +function testX25519() { + test(253, 'ECDH', 'X25519', null); ntests++; } @@ -90,5 +95,5 @@ testNOT_PFS(); process.on('exit', function() { assert.strictEqual(ntests, nsuccess); - assert.strictEqual(ntests, 5); + assert.strictEqual(ntests, 6); }); From 431203204f54b9a76bac6491d84ba08b6218c9cd Mon Sep 17 00:00:00 2001 From: Anatoli Papirovski Date: Mon, 16 Apr 2018 22:03:10 +0200 Subject: [PATCH 58/76] http2: fix responses to long payload reqs When a request with a long payload is received, http2 does not allow a response that does not process all the incoming payload. Add a conditional Http2Stream.close call that runs only if the user hasn't attempted to read the stream. PR-URL: https://github.com/nodejs/node/pull/20084 Fixes: https://github.com/nodejs/node/issues/20060 Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Matteo Collina --- lib/internal/http2/core.js | 181 ++++++++++-------- src/node_http2.cc | 69 +++++-- src/node_http2.h | 10 +- test/fixtures/person-large.jpg | Bin 0 -> 139837 bytes test/parallel/test-http2-client-destroy.js | 18 ++ ...t-http2-client-rststream-before-connect.js | 10 +- .../test-http2-client-upload-reject.js | 48 +++++ test/parallel/test-http2-client-upload.js | 2 +- test/parallel/test-http2-large-write-close.js | 44 +++++ test/parallel/test-http2-perf_hooks.js | 2 +- 10 files changed, 279 insertions(+), 105 deletions(-) create mode 100644 test/fixtures/person-large.jpg create mode 100644 test/parallel/test-http2-client-upload-reject.js create mode 100644 test/parallel/test-http2-large-write-close.js diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index 495fa60ba39ce3..be5d08a0b0a1f5 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -206,6 +206,7 @@ const STREAM_FLAGS_CLOSED = 0x2; const STREAM_FLAGS_HEADERS_SENT = 0x4; const STREAM_FLAGS_HEAD_REQUEST = 0x8; const STREAM_FLAGS_ABORTED = 0x10; +const STREAM_FLAGS_HAS_TRAILERS = 0x20; const SESSION_FLAGS_PENDING = 0x0; const SESSION_FLAGS_READY = 0x1; @@ -330,26 +331,13 @@ function onStreamClose(code) { if (stream.destroyed) return; - const state = stream[kState]; - debug(`Http2Stream ${stream[kID]} [Http2Session ` + `${sessionName(stream[kSession][kType])}]: closed with code ${code}`); - if (!stream.closed) { - // Clear timeout and remove timeout listeners - stream.setTimeout(0); - stream.removeAllListeners('timeout'); + if (!stream.closed) + closeStream(stream, code, false); - // Set the state flags - state.flags |= STREAM_FLAGS_CLOSED; - state.rstCode = code; - - // Close the writable side of the stream - abort(stream); - stream.end(); - } - - state.fd = -1; + stream[kState].fd = -1; // Defer destroy we actually emit end. if (stream._readableState.endEmitted || code !== NGHTTP2_NO_ERROR) { // If errored or ended, we can destroy immediately. @@ -504,7 +492,7 @@ function requestOnConnect(headers, options) { // At this point, the stream should have already been destroyed during // the session.destroy() method. Do nothing else. - if (session.destroyed) + if (session === undefined || session.destroyed) return; // If the session was closed while waiting for the connect, destroy @@ -1412,6 +1400,9 @@ class ClientHttp2Session extends Http2Session { if (options.endStream) stream.end(); + if (options.waitForTrailers) + stream[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + const onConnect = requestOnConnect.bind(stream, headersList, options); if (this.connecting) { this.on('connect', onConnect); @@ -1445,8 +1436,11 @@ function afterDoStreamWrite(status, handle) { } function streamOnResume() { - if (!this.destroyed && !this.pending) + if (!this.destroyed && !this.pending) { + if (!this[kState].didRead) + this[kState].didRead = true; this[kHandle].readStart(); + } } function streamOnPause() { @@ -1454,16 +1448,6 @@ function streamOnPause() { this[kHandle].readStop(); } -// If the writable side of the Http2Stream is still open, emit the -// 'aborted' event and set the aborted flag. -function abort(stream) { - if (!stream.aborted && - !(stream._writableState.ended || stream._writableState.ending)) { - stream[kState].flags |= STREAM_FLAGS_ABORTED; - stream.emit('aborted'); - } -} - function afterShutdown() { this.callback(); const stream = this.handle[kOwner]; @@ -1471,6 +1455,51 @@ function afterShutdown() { stream[kMaybeDestroy](); } +function closeStream(stream, code, shouldSubmitRstStream = true) { + const state = stream[kState]; + state.flags |= STREAM_FLAGS_CLOSED; + state.rstCode = code; + + // Clear timeout and remove timeout listeners + stream.setTimeout(0); + stream.removeAllListeners('timeout'); + + const { ending, finished } = stream._writableState; + + if (!ending) { + // If the writable side of the Http2Stream is still open, emit the + // 'aborted' event and set the aborted flag. + if (!stream.aborted) { + state.flags |= STREAM_FLAGS_ABORTED; + stream.emit('aborted'); + } + + // Close the writable side. + stream.end(); + } + + if (shouldSubmitRstStream) { + const finishFn = finishCloseStream.bind(stream, code); + if (!ending || finished || code !== NGHTTP2_NO_ERROR) + finishFn(); + else + stream.once('finish', finishFn); + } +} + +function finishCloseStream(code) { + const rstStreamFn = submitRstStream.bind(this, code); + // If the handle has not yet been assigned, queue up the request to + // ensure that the RST_STREAM frame is sent after the stream ID has + // been determined. + if (this.pending) { + this.push(null); + this.once('ready', rstStreamFn); + return; + } + rstStreamFn(); +} + // An Http2Stream is a Duplex stream that is backed by a // node::http2::Http2Stream handle implementing StreamBase. class Http2Stream extends Duplex { @@ -1490,6 +1519,7 @@ class Http2Stream extends Duplex { this[kTimeout] = null; this[kState] = { + didRead: false, flags: STREAM_FLAGS_PENDING, rstCode: NGHTTP2_NO_ERROR, writeQueueSize: 0, @@ -1756,6 +1786,8 @@ class Http2Stream extends Duplex { throw headersList; this[kSentTrailers] = headers; + this[kState].flags &= ~STREAM_FLAGS_HAS_TRAILERS; + const ret = this[kHandle].trailers(headersList); if (ret < 0) this.destroy(new NghttpError(ret)); @@ -1786,38 +1818,13 @@ class Http2Stream extends Duplex { if (callback !== undefined && typeof callback !== 'function') throw new ERR_INVALID_CALLBACK(); - // Clear timeout and remove timeout listeners - this.setTimeout(0); - this.removeAllListeners('timeout'); - - // Close the writable - abort(this); - this.end(); - if (this.closed) return; - const state = this[kState]; - state.flags |= STREAM_FLAGS_CLOSED; - state.rstCode = code; - - if (callback !== undefined) { + if (callback !== undefined) this.once('close', callback); - } - - if (this[kHandle] === undefined) - return; - const rstStreamFn = submitRstStream.bind(this, code); - // If the handle has not yet been assigned, queue up the request to - // ensure that the RST_STREAM frame is sent after the stream ID has - // been determined. - if (this.pending) { - this.push(null); - this.once('ready', rstStreamFn); - return; - } - rstStreamFn(); + closeStream(this, code); } // Called by this.destroy(). @@ -1832,26 +1839,19 @@ class Http2Stream extends Duplex { debug(`Http2Stream ${this[kID] || ''} [Http2Session ` + `${sessionName(session[kType])}]: destroying stream`); const state = this[kState]; - const code = state.rstCode = - err != null ? - NGHTTP2_INTERNAL_ERROR : - state.rstCode || NGHTTP2_NO_ERROR; - if (handle !== undefined) { - // If the handle exists, we need to close, then destroy the handle - this.close(code); - if (!this._readableState.ended && !this._readableState.ending) - this.push(null); + const code = err != null ? + NGHTTP2_INTERNAL_ERROR : (state.rstCode || NGHTTP2_NO_ERROR); + + const hasHandle = handle !== undefined; + + if (!this.closed) + closeStream(this, code, hasHandle); + this.push(null); + + if (hasHandle) { handle.destroy(); session[kState].streams.delete(id); } else { - // Clear timeout and remove timeout listeners - this.setTimeout(0); - this.removeAllListeners('timeout'); - - state.flags |= STREAM_FLAGS_CLOSED; - abort(this); - this.end(); - this.push(null); session[kState].pendingStreams.delete(this); } @@ -1884,13 +1884,23 @@ class Http2Stream extends Duplex { } // TODO(mcollina): remove usage of _*State properties - if (this._readableState.ended && - this._writableState.ended && - this._writableState.pendingcb === 0 && - this.closed) { - this.destroy(); - // This should return, but eslint complains. - // return + if (this._writableState.ended && this._writableState.pendingcb === 0) { + if (this._readableState.ended && this.closed) { + this.destroy(); + return; + } + + // We've submitted a response from our server session, have not attempted + // to process any incoming data, and have no trailers. This means we can + // attempt to gracefully close the session. + const state = this[kState]; + if (this.headersSent && + this[kSession][kType] === NGHTTP2_SESSION_SERVER && + !(state.flags & STREAM_FLAGS_HAS_TRAILERS) && + !state.didRead && + !this._readableState.resumeScheduled) { + this.close(); + } } } } @@ -2095,7 +2105,6 @@ function afterOpen(session, options, headers, streamOptions, err, fd) { } if (this.destroyed || this.closed) { tryClose(fd); - abort(this); return; } state.fd = fd; @@ -2224,8 +2233,10 @@ class ServerHttp2Stream extends Http2Stream { if (options.endStream) streamOptions |= STREAM_OPTION_EMPTY_PAYLOAD; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + state.flags |= STREAM_FLAGS_HAS_TRAILERS; + } headers = processHeaders(headers); const statusCode = headers[HTTP2_HEADER_STATUS] |= 0; @@ -2285,8 +2296,10 @@ class ServerHttp2Stream extends Http2Stream { } let streamOptions = 0; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + } if (typeof fd !== 'number') throw new ERR_INVALID_ARG_TYPE('fd', 'number', fd); @@ -2346,8 +2359,10 @@ class ServerHttp2Stream extends Http2Stream { } let streamOptions = 0; - if (options.waitForTrailers) + if (options.waitForTrailers) { streamOptions |= STREAM_OPTION_GET_TRAILERS; + this[kState].flags |= STREAM_FLAGS_HAS_TRAILERS; + } const session = this[kSession]; debug(`Http2Stream ${this[kID]} [Http2Session ` + diff --git a/src/node_http2.cc b/src/node_http2.cc index 1c5c68f09471f3..05d9243ee30ec0 100644 --- a/src/node_http2.cc +++ b/src/node_http2.cc @@ -1364,16 +1364,35 @@ void Http2Session::MaybeScheduleWrite() { // storage for data and metadata that was associated with these writes. void Http2Session::ClearOutgoing(int status) { CHECK_NE(flags_ & SESSION_STATE_SENDING, 0); - flags_ &= ~SESSION_STATE_SENDING; - for (const nghttp2_stream_write& wr : outgoing_buffers_) { - WriteWrap* wrap = wr.req_wrap; - if (wrap != nullptr) - wrap->Done(status); + if (outgoing_buffers_.size() > 0) { + outgoing_storage_.clear(); + + for (const nghttp2_stream_write& wr : outgoing_buffers_) { + WriteWrap* wrap = wr.req_wrap; + if (wrap != nullptr) + wrap->Done(status); + } + + outgoing_buffers_.clear(); } - outgoing_buffers_.clear(); - outgoing_storage_.clear(); + flags_ &= ~SESSION_STATE_SENDING; + + // Now that we've finished sending queued data, if there are any pending + // RstStreams we should try sending again and then flush them one by one. + if (pending_rst_streams_.size() > 0) { + std::vector current_pending_rst_streams; + pending_rst_streams_.swap(current_pending_rst_streams); + + SendPendingData(); + + for (int32_t stream_id : current_pending_rst_streams) { + Http2Stream* stream = FindStream(stream_id); + if (stream != nullptr) + stream->FlushRstStream(); + } + } } // Queue a given block of data for sending. This always creates a copy, @@ -1397,18 +1416,19 @@ void Http2Session::CopyDataIntoOutgoing(const uint8_t* src, size_t src_length) { // chunk out to the i/o socket to be sent. This is a particularly hot method // that will generally be called at least twice be event loop iteration. // This is a potential performance optimization target later. -void Http2Session::SendPendingData() { +// Returns non-zero value if a write is already in progress. +uint8_t Http2Session::SendPendingData() { DEBUG_HTTP2SESSION(this, "sending pending data"); // Do not attempt to send data on the socket if the destroying flag has // been set. That means everything is shutting down and the socket // will not be usable. if (IsDestroyed()) - return; + return 0; flags_ &= ~SESSION_STATE_WRITE_SCHEDULED; // SendPendingData should not be called recursively. if (flags_ & SESSION_STATE_SENDING) - return; + return 1; // This is cleared by ClearOutgoing(). flags_ |= SESSION_STATE_SENDING; @@ -1432,15 +1452,15 @@ void Http2Session::SendPendingData() { // does take care of things like closing the individual streams after // a socket has been torn down, so we still need to call it. ClearOutgoing(UV_ECANCELED); - return; + return 0; } // Part Two: Pass Data to the underlying stream size_t count = outgoing_buffers_.size(); if (count == 0) { - flags_ &= ~SESSION_STATE_SENDING; - return; + ClearOutgoing(0); + return 0; } MaybeStackBuffer bufs; bufs.AllocateSufficientStorage(count); @@ -1471,6 +1491,8 @@ void Http2Session::SendPendingData() { DEBUG_HTTP2SESSION2(this, "wants data in return? %d", nghttp2_session_want_read(session_)); + + return 0; } @@ -1830,12 +1852,25 @@ int Http2Stream::SubmitPriority(nghttp2_priority_spec* prispec, // peer. void Http2Stream::SubmitRstStream(const uint32_t code) { CHECK(!this->IsDestroyed()); + code_ = code; + // If possible, force a purge of any currently pending data here to make sure + // it is sent before closing the stream. If it returns non-zero then we need + // to wait until the current write finishes and try again to avoid nghttp2 + // behaviour where it prioritizes RstStream over everything else. + if (session_->SendPendingData() != 0) { + session_->AddPendingRstStream(id_); + return; + } + + FlushRstStream(); +} + +void Http2Stream::FlushRstStream() { + if (IsDestroyed()) + return; Http2Scope h2scope(this); - // Force a purge of any currently pending data here to make sure - // it is sent before closing the stream. - session_->SendPendingData(); CHECK_EQ(nghttp2_submit_rst_stream(**session_, NGHTTP2_FLAG_NONE, - id_, code), 0); + id_, code_), 0); } diff --git a/src/node_http2.h b/src/node_http2.h index 87c929cdea12f9..da404841450f27 100644 --- a/src/node_http2.h +++ b/src/node_http2.h @@ -591,6 +591,8 @@ class Http2Stream : public AsyncWrap, // Submits an RST_STREAM frame using the given code void SubmitRstStream(const uint32_t code); + void FlushRstStream(); + // Submits a PUSH_PROMISE frame with this stream as the parent. Http2Stream* SubmitPushPromise( nghttp2_nv* nva, @@ -797,7 +799,7 @@ class Http2Session : public AsyncWrap, public StreamListener { bool Ping(v8::Local function); - void SendPendingData(); + uint8_t SendPendingData(); // Submits a new request. If the request is a success, assigned // will be a pointer to the Http2Stream instance assigned. @@ -845,6 +847,11 @@ class Http2Session : public AsyncWrap, public StreamListener { size_t self_size() const override { return sizeof(*this); } + // Schedule an RstStream for after the current write finishes. + inline void AddPendingRstStream(int32_t stream_id) { + pending_rst_streams_.emplace_back(stream_id); + } + // Handle reads/writes from the underlying network transport. void OnStreamRead(ssize_t nread, const uv_buf_t& buf) override; void OnStreamAfterWrite(WriteWrap* w, int status) override; @@ -1049,6 +1056,7 @@ class Http2Session : public AsyncWrap, public StreamListener { std::vector outgoing_buffers_; std::vector outgoing_storage_; + std::vector pending_rst_streams_; void CopyDataIntoOutgoing(const uint8_t* src, size_t src_length); void ClearOutgoing(int status); diff --git a/test/fixtures/person-large.jpg b/test/fixtures/person-large.jpg new file mode 100644 index 0000000000000000000000000000000000000000..3d0d0af42375c3e696731294deea165f132a5797 GIT binary patch literal 139837 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

00jHv6S|N{HyjWGAVepgZhO<Q%=L+F4!0 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%0D{5QF)fKDd}br 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 E15V*r*Z=?k literal 0 HcmV?d00001 diff --git a/test/parallel/test-http2-client-destroy.js b/test/parallel/test-http2-client-destroy.js index 09ca011c736c96..e641335e751287 100644 --- a/test/parallel/test-http2-client-destroy.js +++ b/test/parallel/test-http2-client-destroy.js @@ -124,3 +124,21 @@ const Countdown = require('../common/countdown'); req.on('error', () => {}); })); } + +// test destroy before connect +{ + const server = h2.createServer(); + server.on('stream', common.mustNotCall()); + + server.listen(0, common.mustCall(() => { + const client = h2.connect(`http://localhost:${server.address().port}`); + + server.on('connection', common.mustCall(() => { + server.close(); + client.close(); + })); + + const req = client.request(); + req.destroy(); + })); +} diff --git a/test/parallel/test-http2-client-rststream-before-connect.js b/test/parallel/test-http2-client-rststream-before-connect.js index 7bace941d1a0af..33e22130aad19b 100644 --- a/test/parallel/test-http2-client-rststream-before-connect.js +++ b/test/parallel/test-http2-client-rststream-before-connect.js @@ -63,8 +63,14 @@ server.listen(0, common.mustCall(() => { message: 'Stream closed with error code NGHTTP2_PROTOCOL_ERROR' })); - req.on('response', common.mustCall()); - req.resume(); + // The `response` event should not fire as the server should receive the + // RST_STREAM frame before it ever has a chance to reply. + req.on('response', common.mustNotCall()); + + // The `end` event should still fire as we close the readable stream by + // pushing a `null` chunk. req.on('end', common.mustCall()); + + req.resume(); req.end(); })); diff --git a/test/parallel/test-http2-client-upload-reject.js b/test/parallel/test-http2-client-upload-reject.js new file mode 100644 index 00000000000000..ece7cbdf233f1f --- /dev/null +++ b/test/parallel/test-http2-client-upload-reject.js @@ -0,0 +1,48 @@ +'use strict'; + +// Verifies that uploading data from a client works + +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const http2 = require('http2'); +const fs = require('fs'); +const fixtures = require('../common/fixtures'); + +const loc = fixtures.path('person-large.jpg'); + +assert(fs.existsSync(loc)); + +fs.readFile(loc, common.mustCall((err, data) => { + assert.ifError(err); + + const server = http2.createServer(); + + server.on('stream', common.mustCall((stream) => { + stream.on('close', common.mustCall(() => { + assert.strictEqual(stream.rstCode, 0); + })); + + stream.respond({ ':status': 400 }); + stream.end(); + })); + + server.listen(0, common.mustCall(() => { + const client = http2.connect(`http://localhost:${server.address().port}`); + + const req = client.request({ ':method': 'POST' }); + req.on('response', common.mustCall((headers) => { + assert.strictEqual(headers[':status'], 400); + })); + + req.resume(); + req.on('end', common.mustCall(() => { + server.close(); + client.close(); + })); + + const str = fs.createReadStream(loc); + str.pipe(req); + })); +})); diff --git a/test/parallel/test-http2-client-upload.js b/test/parallel/test-http2-client-upload.js index 70a8ff3ced01c6..78c6d47cbb4f44 100644 --- a/test/parallel/test-http2-client-upload.js +++ b/test/parallel/test-http2-client-upload.js @@ -11,7 +11,7 @@ const fs = require('fs'); const fixtures = require('../common/fixtures'); const Countdown = require('../common/countdown'); -const loc = fixtures.path('person.jpg'); +const loc = fixtures.path('person-large.jpg'); let fileData; assert(fs.existsSync(loc)); diff --git a/test/parallel/test-http2-large-write-close.js b/test/parallel/test-http2-large-write-close.js new file mode 100644 index 00000000000000..f9dee357d6da7b --- /dev/null +++ b/test/parallel/test-http2-large-write-close.js @@ -0,0 +1,44 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) + common.skip('missing crypto'); +const assert = require('assert'); +const fixtures = require('../common/fixtures'); +const http2 = require('http2'); + +const content = Buffer.alloc(1e5, 0x44); + +const server = http2.createSecureServer({ + key: fixtures.readKey('agent1-key.pem'), + cert: fixtures.readKey('agent1-cert.pem') +}); +server.on('stream', common.mustCall((stream) => { + stream.respond({ + 'Content-Type': 'application/octet-stream', + 'Content-Length': (content.length.toString() * 2), + 'Vary': 'Accept-Encoding' + }); + + stream.write(content); + stream.write(content); + stream.end(); + stream.close(); +})); + +server.listen(0, common.mustCall(() => { + const client = http2.connect(`https://localhost:${server.address().port}`, + { rejectUnauthorized: false }); + + const req = client.request({ ':path': '/' }); + req.end(); + + let receivedBufferLength = 0; + req.on('data', common.mustCallAtLeast((buf) => { + receivedBufferLength += buf.length; + }, 1)); + req.on('close', common.mustCall(() => { + assert.strictEqual(receivedBufferLength, content.length * 2); + client.close(); + server.close(); + })); +})); diff --git a/test/parallel/test-http2-perf_hooks.js b/test/parallel/test-http2-perf_hooks.js index 07d9c55ed7e0d2..5dd8ad0f6d883b 100644 --- a/test/parallel/test-http2-perf_hooks.js +++ b/test/parallel/test-http2-perf_hooks.js @@ -26,7 +26,7 @@ const obs = new PerformanceObserver(common.mustCall((items) => { switch (entry.type) { case 'server': assert.strictEqual(entry.streamCount, 1); - assert.strictEqual(entry.framesReceived, 5); + assert(entry.framesReceived >= 3); break; case 'client': assert.strictEqual(entry.streamCount, 1); From fd5901651355986b3728d8ea9af4428715a31106 Mon Sep 17 00:00:00 2001 From: Vse Mozhet Byt Date: Sun, 29 Apr 2018 01:26:30 +0300 Subject: [PATCH 59/76] doc: add missing backticks in n-api.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Codify types, variable names, and code fragments checking patterns I've managed to think of. Some nits were also fixed in passing (add missing periods, remove extra line breaks etc). PR-URL: https://github.com/nodejs/node/pull/20390 Reviewed-By: Tobias Nießen Reviewed-By: Trivikram Kamat Reviewed-By: Gabriel Schulhof Reviewed-By: Ruben Bridgewater --- doc/api/n-api.md | 415 +++++++++++++++++++++++------------------------ 1 file changed, 204 insertions(+), 211 deletions(-) diff --git a/doc/api/n-api.md b/doc/api/n-api.md index 26b5e87463948e..adb8647b399ecd 100644 --- a/doc/api/n-api.md +++ b/doc/api/n-api.md @@ -185,7 +185,6 @@ typedef void (*napi_finalize)(napi_env env, void* finalize_hint); ``` - #### napi_async_execute_callback Function pointer used with functions that support asynchronous operations. Callback functions must statisfy the following signature: @@ -223,7 +222,7 @@ In cases where a return value other than `napi_ok` or must be called to check if an exception is pending. See the section on exceptions for more details. -The full set of possible napi_status values is defined +The full set of possible `napi_status` values is defined in `napi_api_types.h`. The `napi_status` return value provides a VM-independent representation of @@ -282,7 +281,6 @@ logging purposes. This API can be called even if there is a pending JavaScript exception. - ### Exceptions Any N-API function call may result in a pending JavaScript exception. This is obviously the case for any function that may cause the execution of @@ -312,10 +310,10 @@ and then continue. This is only recommended in specific cases where it is known that the exception can be safely handled. In these cases [`napi_get_and_clear_last_exception`][] can be used to get and clear the exception. On success, result will contain the handle to -the last JavaScript Object thrown. If it is determined, after +the last JavaScript `Object` thrown. If it is determined, after retrieving the exception, the exception cannot be handled after all it can be re-thrown it with [`napi_throw`][] where error is the -JavaScript Error object to be thrown. +JavaScript `Error` object to be thrown. The following utility functions are also available in case native code needs to throw an exception or determine if a `napi_value` is an instance @@ -324,10 +322,10 @@ of a JavaScript `Error` object: [`napi_throw_error`][], [`napi_is_error`][]. The following utility functions are also available in case native -code needs to create an Error object: [`napi_create_error`][], -[`napi_create_type_error`][], and [`napi_create_range_error`][]. -where result is the napi_value that refers to the newly created -JavaScript Error object. +code needs to create an `Error` object: [`napi_create_error`][], +[`napi_create_type_error`][], and [`napi_create_range_error`][], +where result is the `napi_value` that refers to the newly created +JavaScript `Error` object. The Node.js project is adding error codes to all of the errors generated internally. The goal is for applications to use these @@ -346,9 +344,9 @@ the name associated with the error is also updated to be: originalName [code] ``` -where originalName is the original name associated with the error -and code is the code that was provided. For example if the code -is 'ERR_ERROR_1' and a TypeError is being created the name will be: +where `originalName` is the original name associated with the error +and `code` is the code that was provided. For example if the code +is `'ERR_ERROR_1'` and a `TypeError` is being created the name will be: ```text TypeError [ERR_ERROR_1] @@ -362,12 +360,11 @@ added: v8.0.0 NODE_EXTERN napi_status napi_throw(napi_env env, napi_value error); ``` - `[in] env`: The environment that the API is invoked under. -- `[in] error`: The `napi_value` for the Error to be thrown. +- `[in] error`: The `napi_value` for the `Error` to be thrown. Returns `napi_ok` if the API succeeded. -This API throws the JavaScript Error provided. - +This API throws the JavaScript `Error` provided. #### napi_throw_error - The `Console` class can be used to create a simple logger with configurable diff --git a/doc/api/crypto.md b/doc/api/crypto.md index 6d99978110141d..010251342d9164 100644 --- a/doc/api/crypto.md +++ b/doc/api/crypto.md @@ -2626,7 +2626,6 @@ the `crypto`, `tls`, and `https` modules and are generally specific to OpenSSL. - [`Buffer`]: buffer.html [`EVP_BytesToKey`]: https://www.openssl.org/docs/man1.1.0/crypto/EVP_BytesToKey.html [`UV_THREADPOOL_SIZE`]: cli.html#cli_uv_threadpool_size_size diff --git a/doc/api/dgram.md b/doc/api/dgram.md index 06c15ffa25c879..b6b974541bdfe7 100644 --- a/doc/api/dgram.md +++ b/doc/api/dgram.md @@ -464,7 +464,6 @@ A socket's address family's ANY address (IPv4 `'0.0.0.0'` or IPv6 `'::'`) can be used to return control of the sockets default outgoing interface to the system for future multicast packets. - ### socket.setMulticastLoopback(flag) * `str` {string} - The `querystring.unescape()` method performs decoding of URL percent-encoded characters on the given `str`. diff --git a/doc/api/readline.md b/doc/api/readline.md index c1e50ef7eee350..d3afe5d9bf5ba2 100644 --- a/doc/api/readline.md +++ b/doc/api/readline.md @@ -320,7 +320,6 @@ added: v0.7.7 The `readline.clearLine()` method clears current line of given [TTY][] stream in a specified direction identified by `dir`. - ## readline.clearScreenDown(stream) ```js @@ -1121,10 +1163,15 @@ function throwingSecond() { function notThrowing() {} // The second argument is a string and the input function threw an Error. -// In that case both cases do not throw as neither is going to try to -// match for the error message thrown by the input function! +// The first case will not throw as it does not match for the error message +// thrown by the input function! assert.throws(throwingFirst, 'Second'); +// In the next example the message has no benefit over the message from the +// error and since it is not clear if the user intended to actually match +// against the error message, Node.js thrown an `ERR_AMBIGUOUS_ARGUMENT` error. assert.throws(throwingSecond, 'Second'); +// Throws an error: +// TypeError [ERR_AMBIGUOUS_ARGUMENT] // The string is only used (as message) in case the function does not throw: assert.throws(notThrowing, 'Second'); @@ -1134,7 +1181,7 @@ assert.throws(notThrowing, 'Second'); assert.throws(throwingSecond, /Second$/); // Does not throw because the error messages match. assert.throws(throwingFirst, /Second$/); -// Throws a error: +// Throws an error: // Error: First // at throwingFirst (repl:2:9) ``` From 4477299b3e1eded5dfda47caf876685e16b46986 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:15:59 +0200 Subject: [PATCH 68/76] doc: improve process event headers The headers should be handled as all others as well and just indicate all arguments. PR-URL: https://github.com/nodejs/node/pull/20312 Reviewed-By: Vse Mozhet Byt Reviewed-By: James M Snell Reviewed-By: Trivikram Kamat --- doc/api/net.md | 2 +- doc/api/process.md | 40 +++++++++++++++++++--------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/doc/api/net.md b/doc/api/net.md index 54f3c2f737a73d..6b8afce4a59121 100644 --- a/doc/api/net.md +++ b/doc/api/net.md @@ -388,7 +388,7 @@ added: v0.3.4 Creates a new socket object. * `options` {Object} Available options are: - * `fd`: {number} If specified, wrap around an existing socket with + * `fd` {number} If specified, wrap around an existing socket with the given file descriptor, otherwise a new socket will be created. * `allowHalfOpen` {boolean} Indicates whether half-opened TCP connections are allowed. See [`net.createServer()`][] and the [`'end'`][] event diff --git a/doc/api/process.md b/doc/api/process.md index ad1c997ae169f6..c973d15e12cef7 100644 --- a/doc/api/process.md +++ b/doc/api/process.md @@ -45,6 +45,8 @@ the IPC channel is closed. added: v0.1.7 --> +* `code` {integer} + The `'exit'` event is emitted when the Node.js process is about to exit as a result of either: @@ -56,7 +58,7 @@ all `'exit'` listeners have finished running the Node.js process will terminate. The listener callback function is invoked with the exit code specified either by the [`process.exitCode`][] property, or the `exitCode` argument passed to the -[`process.exit()`] method, as the only argument. +[`process.exit()`] method. ```js process.on('exit', (code) => { @@ -82,16 +84,15 @@ process.on('exit', (code) => { added: v0.5.10 --> +* `message` {Object} a parsed JSON object or primitive value. +* `sendHandle` {net.Server|net.Socket} a [`net.Server`][] or [`net.Socket`][] + object, or undefined. + If the Node.js process is spawned with an IPC channel (see the [Child Process][] and [Cluster][] documentation), the `'message'` event is emitted whenever a message sent by a parent process using [`childprocess.send()`][] is received by the child process. -The listener callback is invoked with the following arguments: -* `message` {Object} a parsed JSON object or primitive value. -* `sendHandle` {net.Server|net.Socket} a [`net.Server`][] or [`net.Socket`][] - object, or undefined. - The message goes through serialization and parsing. The resulting message might not be the same as what is originally sent. @@ -100,13 +101,12 @@ not be the same as what is originally sent. added: v1.4.1 --> +* `promise` {Promise} The late handled promise. + The `'rejectionHandled'` event is emitted whenever a `Promise` has been rejected and an error handler was attached to it (using [`promise.catch()`][], for example) later than one turn of the Node.js event loop. -The listener callback is invoked with a reference to the rejected `Promise` as -the only argument. - The `Promise` object would have previously been emitted in an `'unhandledRejection'` event, but during the course of processing gained a rejection handler. @@ -129,11 +129,11 @@ when the list of unhandled rejections shrinks. ```js const unhandledRejections = new Map(); -process.on('unhandledRejection', (reason, p) => { - unhandledRejections.set(p, reason); +process.on('unhandledRejection', (reason, promise) => { + unhandledRejections.set(promise, reason); }); -process.on('rejectionHandled', (p) => { - unhandledRejections.delete(p); +process.on('rejectionHandled', (promise) => { + unhandledRejections.delete(promise); }); ``` @@ -261,6 +261,12 @@ being emitted. Alternatively, the [`'rejectionHandled'`][] event may be used. added: v6.0.0 --> +* `warning` {Error} Key properties of the warning are: + * `name` {string} The name of the warning. **Default:** `'Warning'`. + * `message` {string} A system-provided description of the warning. + * `stack` {string} A stack trace to the location in the code where the warning + was issued. + The `'warning'` event is emitted whenever Node.js emits a process warning. A process warning is similar to an error in that it describes exceptional @@ -269,14 +275,6 @@ are not part of the normal Node.js and JavaScript error handling flow. Node.js can emit warnings whenever it detects bad coding practices that could lead to sub-optimal application performance, bugs, or security vulnerabilities. -The listener function is called with a single `warning` argument whose value is -an `Error` object. There are three key properties that describe the warning: - -* `name` {string} The name of the warning (currently `'Warning'` by default). -* `message` {string} A system-provided description of the warning. -* `stack` {string} A stack trace to the location in the code where the warning - was issued. - ```js process.on('warning', (warning) => { console.warn(warning.name); // Print the warning name From bd44f4dd47e5771d55a42b3dbd7b52b9d6160f38 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:13:39 +0200 Subject: [PATCH 69/76] http2: fix ping callback In case there was no ack, the callback would have returned more than the error as return value. This makes sure that is not the case anymore. PR-URL: https://github.com/nodejs/node/pull/20311 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Trivikram Kamat --- lib/internal/http2/core.js | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/internal/http2/core.js b/lib/internal/http2/core.js index be5d08a0b0a1f5..a9fdcb659544e5 100644 --- a/lib/internal/http2/core.js +++ b/lib/internal/http2/core.js @@ -704,8 +704,11 @@ const proxySocketHandler = { // data received on the PING acknowlegement. function pingCallback(cb) { return function pingCallback(ack, duration, payload) { - const err = ack ? null : new ERR_HTTP2_PING_CANCEL(); - cb(err, duration, payload); + if (ack) { + cb(null, duration, payload); + } else { + cb(new ERR_HTTP2_PING_CANCEL()); + } }; } From ad4dcbb9d427a3f2eb1c571e8d3845a92663c9aa Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 02:14:25 +0200 Subject: [PATCH 70/76] test: verify arguments length in common.expectsError If `common.expectsError` is used as a callback, it will now also verify that there is only one argument (the expected error). PR-URL: https://github.com/nodejs/node/pull/20311 Reviewed-By: James M Snell Reviewed-By: Matteo Collina Reviewed-By: Trivikram Kamat --- test/common/index.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test/common/index.js b/test/common/index.js index 95bb8dd804881f..bbd2b62d7da768 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -708,6 +708,11 @@ exports.expectsError = function expectsError(fn, settings, exact) { } function innerFn(error) { + if (arguments.length !== 1) { + // Do not use `assert.strictEqual()` to prevent `util.inspect` from + // always being called. + assert.fail(`Expected one argument, got ${util.inspect(arguments)}`); + } const descriptor = Object.getOwnPropertyDescriptor(error, 'message'); assert.strictEqual(descriptor.enumerable, false, 'The error message should be non-enumerable'); From db1f7080e40b475b7b6259de8a095e883f7e7907 Mon Sep 17 00:00:00 2001 From: Ruben Bridgewater Date: Thu, 26 Apr 2018 05:44:14 +0200 Subject: [PATCH 71/76] test: fix a TODO and remove obsolete TODOs This removes outdated TODOs and adds a test for invalid input in `fs.copyFile` and solves a TODO by doing so. PR-URL: https://github.com/nodejs/node/pull/20319 Reviewed-By: Daniel Bevenius Reviewed-By: Colin Ihrig Reviewed-By: Trivikram Kamat Reviewed-By: James M Snell --- lib/url.js | 3 --- test/parallel/test-cluster-http-pipe.js | 1 - test/parallel/test-fs-error-messages.js | 23 ++++++++++---------- test/parallel/test-util-isDeepStrictEqual.js | 2 -- 4 files changed, 11 insertions(+), 18 deletions(-) diff --git a/lib/url.js b/lib/url.js index ac9879a650fce6..e4326e80b5d948 100644 --- a/lib/url.js +++ b/lib/url.js @@ -281,9 +281,6 @@ Url.prototype.parse = function parse(url, parseQueryString, slashesDenoteHost) { // http://a@b@c/ => user:a@b host:c // http://a@b?@c => user:a host:b path:/?@c - // v0.12 TODO(isaacs): This is not quite how Chrome does things. - // Review our test case against browsers more comprehensively. - var hostEnd = -1; var atSign = -1; var nonHost = -1; diff --git a/test/parallel/test-cluster-http-pipe.js b/test/parallel/test-cluster-http-pipe.js index 9e58fb297b28fe..9e039541cd26f1 100644 --- a/test/parallel/test-cluster-http-pipe.js +++ b/test/parallel/test-cluster-http-pipe.js @@ -45,7 +45,6 @@ if (cluster.isMaster) { http.createServer(common.mustCall((req, res) => { assert.strictEqual(req.connection.remoteAddress, undefined); assert.strictEqual(req.connection.localAddress, undefined); - // TODO common.PIPE? res.writeHead(200); res.end('OK'); diff --git a/test/parallel/test-fs-error-messages.js b/test/parallel/test-fs-error-messages.js index 61e51585a028c2..28141f33f62965 100644 --- a/test/parallel/test-fs-error-messages.js +++ b/test/parallel/test-fs-error-messages.js @@ -636,22 +636,21 @@ if (!common.isAIX) { ); } -// copyFile with invalid flags +// Check copyFile with invalid flags. { - const validateError = (err) => { - assert.strictEqual(err.message, - 'EINVAL: invalid argument, copyfile ' + - `'${existingFile}' -> '${nonexistentFile}'`); - assert.strictEqual(err.errno, uv.UV_EINVAL); - assert.strictEqual(err.code, 'EINVAL'); - assert.strictEqual(err.syscall, 'copyfile'); - return true; + const validateError = { + // TODO: Make sure the error message always also contains the src. + message: `EINVAL: invalid argument, copyfile -> '${nonexistentFile}'`, + errno: uv.UV_EINVAL, + code: 'EINVAL', + syscall: 'copyfile' }; - // TODO(joyeecheung): test fs.copyFile() when uv_fs_copyfile does not - // keep the loop open when the flags are invalid. - // See https://github.com/libuv/libuv/pull/1747 + fs.copyFile(existingFile, nonexistentFile, -1, + common.expectsError(validateError)); + validateError.message = 'EINVAL: invalid argument, copyfile ' + + `'${existingFile}' -> '${nonexistentFile}'`; assert.throws( () => fs.copyFileSync(existingFile, nonexistentFile, -1), validateError diff --git a/test/parallel/test-util-isDeepStrictEqual.js b/test/parallel/test-util-isDeepStrictEqual.js index 356a9a71324971..938781a43084a5 100644 --- a/test/parallel/test-util-isDeepStrictEqual.js +++ b/test/parallel/test-util-isDeepStrictEqual.js @@ -419,8 +419,6 @@ notUtilIsDeepStrict([1, , , 3], [1, , , 3, , , ]); const err3 = new TypeError('foo1'); notUtilIsDeepStrict(err1, err2, assert.AssertionError); notUtilIsDeepStrict(err1, err3, assert.AssertionError); - // TODO: evaluate if this should throw or not. The same applies for RegExp - // Date and any object that has the same keys but not the same prototype. notUtilIsDeepStrict(err1, {}, assert.AssertionError); } From 6474b70309e6e27ea729fcfc4d6edcc94ba1ea8f Mon Sep 17 00:00:00 2001 From: Ben Noordhuis Date: Thu, 26 Apr 2018 09:03:26 +0200 Subject: [PATCH 72/76] build: remove --xcode configure switch MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `./configure --xcode` ostensibly let you built with the Xcode IDE but it has never been tested regularly since its introduction in 2012 and probably has been broken for years. Remove it. PR-URL: https://github.com/nodejs/node/pull/20328 Fixes: https://github.com/nodejs/node/issues/20324 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Gibson Fahnestock Reviewed-By: Michaël Zasso Reviewed-By: Beth Griggs Reviewed-By: Daniel Bevenius Reviewed-By: Joyee Cheung Reviewed-By: Colin Ihrig Reviewed-By: James M Snell Reviewed-By: Gus Caplan --- configure | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/configure b/configure index c1170f9a132a16..17e13a48d47e5a 100755 --- a/configure +++ b/configure @@ -501,11 +501,6 @@ parser.add_option('--without-node-options', dest='without_node_options', help='build without NODE_OPTIONS support') -parser.add_option('--xcode', - action='store_true', - dest='use_xcode', - help='generate build files for use with xcode') - parser.add_option('--ninja', action='store_true', dest='use_ninja', @@ -1005,9 +1000,6 @@ def configure_node(o): o['variables']['asan'] = int(options.enable_asan or 0) - if options.use_xcode and options.use_ninja: - raise Exception('--xcode and --ninja cannot be used together.') - if options.coverage: o['variables']['coverage'] = 'true' else: @@ -1530,7 +1522,6 @@ write('config.gypi', do_not_edit + config = { 'BUILDTYPE': 'Debug' if options.debug else 'Release', - 'USE_XCODE': str(int(options.use_xcode or 0)), 'PYTHON': sys.executable, 'NODE_TARGET_TYPE': variables['node_target_type'], } @@ -1549,9 +1540,7 @@ write('config.mk', do_not_edit + config) gyp_args = ['--no-parallel'] -if options.use_xcode: - gyp_args += ['-f', 'xcode'] -elif options.use_ninja: +if options.use_ninja: gyp_args += ['-f', 'ninja'] elif flavor == 'win' and sys.platform != 'msys': gyp_args += ['-f', 'msvs', '-G', 'msvs_version=auto'] From b7f6fcb489b4c14bef4d56694185cc6da23b716a Mon Sep 17 00:00:00 2001 From: Julien Fontanet Date: Thu, 26 Apr 2018 11:53:23 +0200 Subject: [PATCH 73/76] stream: fix error handling with async iteration Fix an issue when an error was emitted by the stream before `iterator.next()` is called. PR-URL: https://github.com/nodejs/node/pull/20329 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: James M Snell Reviewed-By: Colin Ihrig Reviewed-By: Anatoli Papirovski --- lib/internal/streams/async_iterator.js | 2 +- .../parallel/test-stream-readable-async-iterators.js | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/internal/streams/async_iterator.js b/lib/internal/streams/async_iterator.js index 9ca8e5ebe23b15..0e34573d877aee 100644 --- a/lib/internal/streams/async_iterator.js +++ b/lib/internal/streams/async_iterator.js @@ -58,7 +58,7 @@ function onError(iter, err) { iter[kLastReject] = null; reject(err); } - iter.error = err; + iter[kError] = err; } function wrapForNext(lastPromise, iter) { diff --git a/test/parallel/test-stream-readable-async-iterators.js b/test/parallel/test-stream-readable-async-iterators.js index b1801a1db3e580..39761b413260f1 100644 --- a/test/parallel/test-stream-readable-async-iterators.js +++ b/test/parallel/test-stream-readable-async-iterators.js @@ -115,6 +115,18 @@ async function tests() { readable.destroy(new Error('kaboom')); })(); + await (async function() { + console.log('call next() after error'); + const readable = new Readable({ + read() {} + }); + const iterator = readable[Symbol.asyncIterator](); + + const err = new Error('kaboom'); + readable.destroy(new Error('kaboom')); + await assert.rejects(iterator.next.bind(iterator), err); + })(); + await (async function() { console.log('read object mode'); const max = 42; From 79e20b57c778a4a596917a39e1320c4ad22cccca Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Sat, 28 Apr 2018 22:38:43 -0700 Subject: [PATCH 74/76] doc: remove parenthetical in onboarding-extras MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove "(I prefer the former)" from onboarding-extras. Without any explanation as to why one might prefer A over B, it probably raises more questions than it answers. PR-URL: https://github.com/nodejs/node/pull/20393 Reviewed-By: Vse Mozhet Byt Reviewed-By: Tobias Nießen Reviewed-By: Richard Lau Reviewed-By: Ruben Bridgewater Reviewed-By: Trivikram Kamat --- doc/onboarding-extras.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/onboarding-extras.md b/doc/onboarding-extras.md index 080918049f66c0..ffc316d7a670b6 100644 --- a/doc/onboarding-extras.md +++ b/doc/onboarding-extras.md @@ -91,7 +91,7 @@ need to be attached anymore, as only important bugfixes will be included. to update from nodejs/node: * `git checkout master` -* `git remote update -p` OR `git fetch --all` (I prefer the former) +* `git remote update -p` OR `git fetch --all` * `git merge --ff-only upstream/master` (or `REMOTENAME/BRANCH`) ## Best practices From c71ee37956d8823e10ad568ff284b8ae9f27c1c2 Mon Sep 17 00:00:00 2001 From: Anna Henningsen Date: Sat, 28 Apr 2018 20:50:19 +0200 Subject: [PATCH 75/76] src: avoid `std::make_unique` Work around https://github.com/nodejs/build/issues/1254, which effectively breaks stress test CI and CITGM, by avoiding `std::make_unique` for now. This workaround should be reverted once that issue is resolved. Refs: https://github.com/nodejs/build/issues/1254 PR-URL: https://github.com/nodejs/node/pull/20386 Reviewed-By: Tiancheng "Timothy" Gu Reviewed-By: Matheus Marchini --- src/inspector_agent.cc | 8 +++++--- src/inspector_io.cc | 4 ++-- src/inspector_js_api.cc | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/inspector_agent.cc b/src/inspector_agent.cc index 1530b206456bb5..4e0c04a7b95527 100644 --- a/src/inspector_agent.cc +++ b/src/inspector_agent.cc @@ -367,8 +367,9 @@ class NodeInspectorClient : public V8InspectorClient { int connectFrontend(std::unique_ptr delegate) { events_dispatched_ = true; int session_id = next_session_id_++; - channels_[session_id] = - std::make_unique(client_, std::move(delegate)); + // TODO(addaleax): Revert back to using make_unique once we get issues + // with CI resolved (i.e. revert the patch that added this comment). + channels_[session_id].reset(new ChannelImpl(client_, std::move(delegate))); return session_id; } @@ -569,7 +570,8 @@ void Agent::Stop() { std::unique_ptr Agent::Connect( std::unique_ptr delegate) { int session_id = client_->connectFrontend(std::move(delegate)); - return std::make_unique(session_id, client_); + return std::unique_ptr( + new InspectorSession(session_id, client_)); } void Agent::WaitForDisconnect() { diff --git a/src/inspector_io.cc b/src/inspector_io.cc index 5e0d29d3caf2cd..38d88d7ab890c9 100644 --- a/src/inspector_io.cc +++ b/src/inspector_io.cc @@ -357,8 +357,8 @@ std::vector InspectorIo::GetTargetIds() const { TransportAction InspectorIo::Attach(int session_id) { Agent* agent = parent_env_->inspector_agent(); fprintf(stderr, "Debugger attached.\n"); - sessions_[session_id] = - agent->Connect(std::make_unique(this, session_id)); + sessions_[session_id] = agent->Connect(std::unique_ptr( + new IoSessionDelegate(this, session_id))); return TransportAction::kAcceptSession; } diff --git a/src/inspector_js_api.cc b/src/inspector_js_api.cc index 3d05b2f6feafff..37cdcecd61dabb 100644 --- a/src/inspector_js_api.cc +++ b/src/inspector_js_api.cc @@ -66,8 +66,8 @@ class JSBindingsConnection : public AsyncWrap { callback_(env->isolate(), callback) { Wrap(wrap, this); Agent* inspector = env->inspector_agent(); - session_ = inspector->Connect( - std::make_unique(env, this)); + session_ = inspector->Connect(std::unique_ptr( + new JSBindingsSessionDelegate(env, this))); } void OnMessage(Local value) { From 7c1ec8761e9bcb44917c590b4c2baa0e8c06e490 Mon Sep 17 00:00:00 2001 From: isurusiri Date: Mon, 30 Apr 2018 18:05:22 +0530 Subject: [PATCH 76/76] doc: modified docs to reflect how to invoke gc on Wrapping C++ objects Currently the documentation for Wrapping C++ Objects doesn't explain how to destruct an object by explicitly invoking the garbage collector. This commit includes a modification to docs that explain how to force the garbage collector to clear objects using V8's command line flags. Fixes: https://github.com/nodejs/node/issues/19876 --- doc/api/addons.md | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) diff --git a/doc/api/addons.md b/doc/api/addons.md index 94c45bfb0e4260..5828574893a89d 100644 --- a/doc/api/addons.md +++ b/doc/api/addons.md @@ -590,8 +590,6 @@ class MyObject : public node::ObjectWrap { static void PlusOne(const v8::FunctionCallbackInfo& args); static v8::Persistent constructor; double value_; - napi_env env_; - napi_ref wrapper_; }; } // namespace demo @@ -606,8 +604,6 @@ prototype: ```cpp // myobject.cc #include "myobject.h" -#include -using std::cout; namespace demo { @@ -629,9 +625,6 @@ MyObject::MyObject(double value) : value_(value) { } MyObject::~MyObject() { - cout << "Deleting object \n"; - napi_delete_reference(env_, wrapper_); - cout << "Deleted object \n"; } void MyObject::Init(Local exports) { @@ -706,20 +699,21 @@ Test it with: // test.js const addon = require('./build/Release/addon'); -let obj = new addon.MyObject(10); +const obj = new addon.MyObject(10); console.log(obj.plusOne()); // Prints: 11 console.log(obj.plusOne()); // Prints: 12 console.log(obj.plusOne()); // Prints: 13 - -obj = null; -global.gc(); -// Prints: Deleting object ``` -Note that, in this example, the garbage collector is executed explicitly to -properly invoke the wrapper objects' destructor. + +The garbage collector can execute forcefully using V8 command line flags +` --gc_global ` and ` --gc_interval `, where ` --gc_global ` forces V8 to +perform a full garbage collection and ` --gc_interval ` forces V8 to +perform garbage collection after a given amount of allocations. Although, +it is recommended to limit V8 command line flags for testing purposes +only, since these are primarily debug flags. ### Factory of wrapped objects