From b5d669a6ea9e8148700c1c84c4ad8ca4f85ffbf5 Mon Sep 17 00:00:00 2001 From: Phillip Johnsen Date: Sun, 7 Mar 2021 00:31:55 +0100 Subject: [PATCH 001/110] build: label PRs with GitHub Action instead of nodejs-github-bot MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Main goal of using a GitHub Action for labelling PRs has been to move the mapping between files changed -> label into a configuration file local to the nodejs/node repository. Previously any changes to that mapping meant having to grasp the nodejs/github-bot project, open a PR with the neccessary changes, get approval from its maintainers before those changes finally got pushed to production. The logic involved in using the file paths / label configuration and resolving the labels to be applied, has been moved into a custom GitHub Action project: nodejs/node-pr-labeler. Aside from removing the external dependency the nodejs-github-bot is in practise, it also reduces the bar for contributors since the resulting project is a lot smaller and less complex than nodejs/github-bot. PR-URL: https://github.com/nodejs/node/pull/38301 Fixes: https://github.com/nodejs/github-bot/issues/294 Reviewed-By: Michaël Zasso Reviewed-By: Richard Lau Reviewed-By: James M Snell Reviewed-By: Rich Trott --- .github/label-pr-config.yml | 195 +++++++++++++++++++++++++++++++++ .github/workflows/label-pr.yml | 14 +++ 2 files changed, 209 insertions(+) create mode 100644 .github/label-pr-config.yml create mode 100644 .github/workflows/label-pr.yml diff --git a/.github/label-pr-config.yml b/.github/label-pr-config.yml new file mode 100644 index 00000000000000..f16b9ba8e51808 --- /dev/null +++ b/.github/label-pr-config.yml @@ -0,0 +1,195 @@ +## Order of entries in this map *does* matter for the resolved labels +## earlier entries override later entries +subSystemLabels: + # src subsystems + /^src\/async-wrap/: c++, async_wrap + /^src\/(?:base64|node_buffer|string_)/: c++, buffer + /^src\/cares/: c++, cares + /^src\/(?:process_wrap|spawn_)/: c++, child_process + /^src\/(?:node_)?crypto/: c++, crypto + /^src\/(?:debug-|node_debug)/: c++, debugger + /^src\/udp_/: c++, dgram + /^src\/(?:fs_|node_file|node_stat_watcher)/: c++, fs + /^src\/node_http_parser/: c++, http_parser + /^src\/node_i18n/: c++, intl + /^src\/uv\./: c++, libuv + /^src\/(?:connect(?:ion)?|pipe|tcp)_/: c++, net + /^src\/node_os/: c++, os + /^src\/(?:node_main|signal_)/: c++, process + /^src\/timer_/: c++, timers + /^src\/(?:CNNICHashWhitelist|node_root_certs|tls_)/: c++, tls + /^src\/tty_/: c++, tty + /^src\/node_url/: c++, url-whatwg + /^src\/node_util/: c++, util + /^src\/(?:node_v8|v8abbr)/: c++, V8 Engine + /^src\/node_contextify/: c++, vm + /^src\/.*win32.*/: c++, windows + /^src\/node_zlib/: c++, zlib + /^src\/tracing/: c++, tracing + /^src\/node_api/: c++, n-api + /^src\/node_http2/: c++, http2, dont-land-on-v6.x + /^src\/node_report/: c++, report + /^src\/node_wasi/: c++, wasi + /^src\/node_worker/: c++, worker + /^src\/quic\/*/: c++, quic, dont-land-on-v14.x, dont-land-on-v12.x + /^src\/node_bob*/: c++, quic, dont-land-on-v14.x, dont-land-on-v12.x + + # don't label python files as c++ + /^src\/.+\.py$/: lib / src, needs-ci + + # properly label changes to v8 inspector integration-related files + /^src\/inspector_/: c++, inspector, needs-ci + + # don't want to label it a c++ update when we're "only" bumping the Node.js version + /^src\/(?!node_version\.h)/: c++ + # BUILDING.md should be marked as 'build' in addition to 'doc' + /^BUILDING\.md$/: build, doc + # meta is a very specific label for things that are policy and or meta-info related + /^([A-Z]+$|CODE_OF_CONDUCT|ROADMAP|WORKING_GROUPS|GOVERNANCE|CHANGELOG|\.mail|\.git.+)/: meta + # things that edit top-level .md files are always a doc change + /^\w+\.md$/: doc + # different variants of *Makefile and build files + /^(tools\/)?(Makefile|BSDmakefile|create_android_makefiles|\.travis\.yml)$/: build, needs-ci + /^tools\/(install\.py|genv8constants\.py|getnodeversion\.py|js2c\.py|utils\.py|configure\.d\/.*)$/: build, needs-ci + /^vcbuild\.bat$/: build, windows, needs-ci + /^(android-)?configure|node\.gyp|common\.gypi$/: build, needs-ci + # more specific tools + /^tools\/gyp/: tools, build, needs-ci + /^tools\/doc\//: tools, doc + /^tools\/icu\//: tools, intl, needs-ci + /^tools\/(?:osx-pkg\.pmdoc|pkgsrc)\//: tools, macos, install + /^tools\/(?:(?:mac)?osx-)/: tools, macos + /^tools\/test-npm/: tools, test, npm + /^tools\/test/: tools, test + /^tools\/(?:certdata|mkssldef|mk-ca-bundle)/: tools, openssl, tls + /^tools\/msvs\//: tools, windows, install, needs-ci + /^tools\/[^/]+\.bat$/: tools, windows, needs-ci + /^tools\/make-v8/: tools, V8 Engine, needs-ci + /^tools\/(code_cache|snapshot|v8_gypfiles)/: needs-ci, + /^tools\/build-addons.js/: needs-ci, + # all other tool changes should be marked as such + /^tools\//: tools + /^\.eslint|\.remark|\.editorconfig/: tools + + ## Dependencies + # libuv needs an explicit mapping, as the ordinary /deps/ mapping below would + # end up as libuv changes labeled with "uv" (which is a non-existing label) + /^deps\/uv\//: libuv + /^deps\/v8\/tools\/gen-postmortem-metadata\.py/: V8 Engine, post-mortem + /^deps\/v8\//: V8 Engine + /^deps\/uvwasi\//: wasi + /^deps\/nghttp2\/nghttp2\.gyp/: build, http2, dont-land-on-v6.x + /^deps\/nghttp2\//: http2, dont-land-on-v6.x + /^deps\/ngtcp2\//: quic, dont-land-on-v14.x, dont-land-on-v12.x + /^deps\/nghttp3\//: quic, dont-land-on-v14.x, dont-land-on-v12.x + /^deps\/([^/]+)/: $1 + + ## JS subsystems + # Oddities first + /^lib\/(punycode|\w+\/freelist|sys\.js)/: '' + /^lib\/constants\.js$/: lib / src + /^lib\/_(debug_agent|debugger)\.js$/: debugger + /^lib(\/\w+)?\/(_)?link(ed)?list/: timers + /^lib\/\w+\/bootstrap_node/: lib / src + /^lib\/\w+\/v8_prof_/: tools + /^lib\/\w+\/socket_list/: net + /^lib\/\w+\/streams$/: stream + /^lib\/.*http2/: http2, dont-land-on-v6.x + /^lib\/worker_threads.js$/: worker + /^lib\/internal\/url\.js$/: url-whatwg + /^lib\/internal\/modules\/esm/: ES Modules + /^lib\/internal\/quic\/*/: quic, dont-land-on-v14.x, dont-land-on-v12.x + + # All other lib/ files map directly + /^lib\/_(\w+)_\w+\.js?$/: $1 # e.g. _(stream)_wrap + /^lib(\/internal)?\/(\w+)\.js?$/: $2 # other .js files + /^lib\/internal\/(\w+)(?:\/|$)/: $1 # internal subfolders + +exlusiveLabels: + # more specific tests + /^test\/addons\//: test, addons + /^test\/debugger\//: test, debugger + /^test\/doctool\//: test, doc, tools + /^test\/timers\//: test, timers + /^test\/pseudo-tty\//: test, tty + /^test\/inspector\//: test, inspector + /^test\/cctest\/test_inspector/: test, inspector + /^test\/cctest\/test_url/: test, url-whatwg + /^test\/addons-napi\//: test, n-api + /^test\/async-hooks\//: test, async_hooks + /^test\/report\//: test, report + /^test\/fixtures\/es-module/: test, ES Modules + /^test\/es-module\//: test, ES Modules + + /^test\//: test + + # specific map for webcrypto.md as it should be labeled 'crypto' + /^doc\/api\/webcrypto.md$/: doc, crypto + # specific map for modules.md as it should be labeled 'module' not 'modules' + /^doc\/api\/modules.md$/: doc, module + # specific map for esm.md as it should be labeled 'ES Modules' not 'esm' + /^doc\/api\/esm.md$/: doc, ES Modules + # n-api is treated separately since it is not a JS core module but is still + # considered a subsystem of sorts + /^doc\/api\/n-api.md$/: doc, n-api + # quic + /^doc\/api\/quic.md$/: doc, quic, dont-land-on-v14.x, dont-land-on-v12.x + # add worker label to PRs that affect doc/api/worker_threads.md + /^doc\/api\/worker_threads.md$/: doc, worker + # automatically tag JS subsystem-specific API doc changes + /^doc\/api\/(\w+)\.md$/: doc, $1 + # add deprecations label to PRs that affect doc/api/deprecations.md + /^doc\/api\/deprecations.md$/: doc, deprecations + + /^doc\//: doc + + # more specific benchmarks + /^benchmark\/buffers\//: benchmark, buffer + /^benchmark\/(?:arrays|es)\//: benchmark, V8 Engine + /^benchmark\/_http/: benchmark, http + /^benchmark\/(?:misc|fixtures)\//: benchmark + /^benchmark\/streams\//: benchmark, stream + /^benchmark\/([^/]+)\//: benchmark, $1 + + /^benchmark\//: benchmark + +allJsSubSystems: + - assert + - async_hooks + - buffer + - child_process + - cluster + - console + - crypto + - debugger + - dgram + - dns + - domain + - events + - esm + - fs + - http + - https + - http2 + - module + - net + - os + - path + - process + - querystring + - quic + - readline + - repl + - report + - stream + - string_decoder + - timers + - tls + - tty + - url + - util + - v8 + - vm + - wasi + - worker + - zlib diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml new file mode 100644 index 00000000000000..7b4f84019e58b6 --- /dev/null +++ b/.github/workflows/label-pr.yml @@ -0,0 +1,14 @@ +name: Label PRs + +on: + pull_request_target: + types: [opened] + +jobs: + label: + runs-on: ubuntu-latest + + steps: + - uses: node/node-pr-labeler@v1 + with: + configuration-path: .github/label-pr-config.yml From 29faf0f12e2056a6c5780cc0cac6405ba724fa9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sun, 25 Apr 2021 10:45:48 +0200 Subject: [PATCH 002/110] build: fix label-pr workflow PR-URL: https://github.com/nodejs/node/pull/38399 Reviewed-By: Zijian Liu Reviewed-By: Anna Henningsen Reviewed-By: Richard Lau Reviewed-By: Darshan Sen Reviewed-By: Colin Ihrig --- .github/workflows/label-pr.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label-pr.yml b/.github/workflows/label-pr.yml index 7b4f84019e58b6..4e56676e41e5ff 100644 --- a/.github/workflows/label-pr.yml +++ b/.github/workflows/label-pr.yml @@ -9,6 +9,6 @@ jobs: runs-on: ubuntu-latest steps: - - uses: node/node-pr-labeler@v1 + - uses: nodejs/node-pr-labeler@v1 with: configuration-path: .github/label-pr-config.yml From 05f41cdbccac9bc6b6e2bd9ff9c6aec5a024a92b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Zasso?= Date: Sat, 17 Apr 2021 09:36:55 +0200 Subject: [PATCH 003/110] deps: patch V8 to 9.0.257.19 Refs: https://github.com/v8/v8/compare/9.0.257.17...9.0.257.19 PR-URL: https://github.com/nodejs/node/pull/38270 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott --- deps/v8/AUTHORS | 1 + deps/v8/include/v8-version.h | 2 +- deps/v8/src/builtins/builtins-array.cc | 24 +++++-- deps/v8/src/compiler/representation-change.cc | 8 +-- deps/v8/src/objects/fixed-array-inl.h | 6 +- deps/v8/src/objects/map-updater.cc | 17 +++-- .../test/mjsunit/compiler/regress-1195777.js | 62 +++++++++++++++++++ .../mjsunit/regress/regress-crbug-1195331.js | 36 +++++++++++ 8 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 deps/v8/test/mjsunit/compiler/regress-1195777.js create mode 100644 deps/v8/test/mjsunit/regress/regress-crbug-1195331.js diff --git a/deps/v8/AUTHORS b/deps/v8/AUTHORS index 42a9f29d89aa93..aa6d32302b3954 100644 --- a/deps/v8/AUTHORS +++ b/deps/v8/AUTHORS @@ -69,6 +69,7 @@ Ben Newman Ben Noordhuis Benjamin Tan Bert Belder +Brendon Tiszka Brice Dobry Burcu Dogan Caitlin Potter diff --git a/deps/v8/include/v8-version.h b/deps/v8/include/v8-version.h index 4826580f7b16aa..9ba8fc6d2ea4b7 100644 --- a/deps/v8/include/v8-version.h +++ b/deps/v8/include/v8-version.h @@ -11,7 +11,7 @@ #define V8_MAJOR_VERSION 9 #define V8_MINOR_VERSION 0 #define V8_BUILD_NUMBER 257 -#define V8_PATCH_LEVEL 17 +#define V8_PATCH_LEVEL 19 // Use 1 for candidates and 0 otherwise. // (Boolean macro values are not supported by all preprocessors.) diff --git a/deps/v8/src/builtins/builtins-array.cc b/deps/v8/src/builtins/builtins-array.cc index 0c3707cee4bbb5..ea21a19a86f3bb 100644 --- a/deps/v8/src/builtins/builtins-array.cc +++ b/deps/v8/src/builtins/builtins-array.cc @@ -650,11 +650,14 @@ class ArrayConcatVisitor { index_offset_(0u), bit_field_(FastElementsField::encode(fast_elements) | ExceedsLimitField::encode(false) | - IsFixedArrayField::encode(storage->IsFixedArray()) | + IsFixedArrayField::encode(storage->IsFixedArray(isolate)) | HasSimpleElementsField::encode( - storage->IsFixedArray() || - !storage->map().IsCustomElementsReceiverMap())) { - DCHECK(!(this->fast_elements() && !is_fixed_array())); + storage->IsFixedArray(isolate) || + // Don't take fast path for storages that might have + // side effects when storing to them. + (!storage->map(isolate).IsCustomElementsReceiverMap() && + !storage->IsJSTypedArray(isolate)))) { + DCHECK_IMPLIES(this->fast_elements(), is_fixed_array()); } ~ArrayConcatVisitor() { clear_storage(); } @@ -1065,8 +1068,8 @@ bool IterateElements(Isolate* isolate, Handle receiver, return IterateElementsSlow(isolate, receiver, length, visitor); } - if (!HasOnlySimpleElements(isolate, *receiver) || - !visitor->has_simple_elements()) { + if (!visitor->has_simple_elements() || + !HasOnlySimpleElements(isolate, *receiver)) { return IterateElementsSlow(isolate, receiver, length, visitor); } Handle array = Handle::cast(receiver); @@ -1082,6 +1085,9 @@ bool IterateElements(Isolate* isolate, Handle receiver, case HOLEY_SEALED_ELEMENTS: case HOLEY_NONEXTENSIBLE_ELEMENTS: case HOLEY_ELEMENTS: { + // Disallow execution so the cached elements won't change mid execution. + DisallowJavascriptExecution no_js(isolate); + // Run through the elements FixedArray and use HasElement and GetElement // to check the prototype for missing elements. Handle elements(FixedArray::cast(array->elements()), isolate); @@ -1108,6 +1114,9 @@ bool IterateElements(Isolate* isolate, Handle receiver, } case HOLEY_DOUBLE_ELEMENTS: case PACKED_DOUBLE_ELEMENTS: { + // Disallow execution so the cached elements won't change mid execution. + DisallowJavascriptExecution no_js(isolate); + // Empty array is FixedArray but not FixedDoubleArray. if (length == 0) break; // Run through the elements FixedArray and use HasElement and GetElement @@ -1144,6 +1153,9 @@ bool IterateElements(Isolate* isolate, Handle receiver, } case DICTIONARY_ELEMENTS: { + // Disallow execution so the cached dictionary won't change mid execution. + DisallowJavascriptExecution no_js(isolate); + Handle dict(array->element_dictionary(), isolate); std::vector indices; indices.reserve(dict->Capacity() / 2); diff --git a/deps/v8/src/compiler/representation-change.cc b/deps/v8/src/compiler/representation-change.cc index 64b274cdccddf4..3d937ada1e7e50 100644 --- a/deps/v8/src/compiler/representation-change.cc +++ b/deps/v8/src/compiler/representation-change.cc @@ -949,10 +949,10 @@ Node* RepresentationChanger::GetWord32RepresentationFor( return node; } else if (output_rep == MachineRepresentation::kWord64) { if (output_type.Is(Type::Signed32()) || - output_type.Is(Type::Unsigned32())) { - op = machine()->TruncateInt64ToInt32(); - } else if (output_type.Is(cache_->kSafeInteger) && - use_info.truncation().IsUsedAsWord32()) { + (output_type.Is(Type::Unsigned32()) && + use_info.type_check() == TypeCheckKind::kNone) || + (output_type.Is(cache_->kSafeInteger) && + use_info.truncation().IsUsedAsWord32())) { op = machine()->TruncateInt64ToInt32(); } else if (use_info.type_check() == TypeCheckKind::kSignedSmall || use_info.type_check() == TypeCheckKind::kSigned32 || diff --git a/deps/v8/src/objects/fixed-array-inl.h b/deps/v8/src/objects/fixed-array-inl.h index b743d15ad898b9..bfd7d9563bc424 100644 --- a/deps/v8/src/objects/fixed-array-inl.h +++ b/deps/v8/src/objects/fixed-array-inl.h @@ -368,7 +368,7 @@ int Search(T* array, Name name, int valid_entries, int* out_insertion_index, double FixedDoubleArray::get_scalar(int index) { DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && map() != GetReadOnlyRoots().fixed_array_map()); - DCHECK(index >= 0 && index < this->length()); + DCHECK_LT(static_cast(index), static_cast(length())); DCHECK(!is_the_hole(index)); return ReadField(kHeaderSize + index * kDoubleSize); } @@ -376,7 +376,7 @@ double FixedDoubleArray::get_scalar(int index) { uint64_t FixedDoubleArray::get_representation(int index) { DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && map() != GetReadOnlyRoots().fixed_array_map()); - DCHECK(index >= 0 && index < this->length()); + DCHECK_LT(static_cast(index), static_cast(length())); int offset = kHeaderSize + index * kDoubleSize; // Bug(v8:8875): Doubles may be unaligned. return base::ReadUnalignedValue(field_address(offset)); @@ -394,6 +394,7 @@ Handle FixedDoubleArray::get(FixedDoubleArray array, int index, void FixedDoubleArray::set(int index, double value) { DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && map() != GetReadOnlyRoots().fixed_array_map()); + DCHECK_LT(static_cast(index), static_cast(length())); int offset = kHeaderSize + index * kDoubleSize; if (std::isnan(value)) { WriteField(offset, std::numeric_limits::quiet_NaN()); @@ -410,6 +411,7 @@ void FixedDoubleArray::set_the_hole(Isolate* isolate, int index) { void FixedDoubleArray::set_the_hole(int index) { DCHECK(map() != GetReadOnlyRoots().fixed_cow_array_map() && map() != GetReadOnlyRoots().fixed_array_map()); + DCHECK_LT(static_cast(index), static_cast(length())); int offset = kHeaderSize + index * kDoubleSize; base::WriteUnalignedValue(field_address(offset), kHoleNanInt64); } diff --git a/deps/v8/src/objects/map-updater.cc b/deps/v8/src/objects/map-updater.cc index 95b435085e2d28..31841992dec18e 100644 --- a/deps/v8/src/objects/map-updater.cc +++ b/deps/v8/src/objects/map-updater.cc @@ -139,11 +139,20 @@ Handle MapUpdater::ReconfigureToDataField(InternalIndex descriptor, if (old_details.constness() == PropertyConstness::kConst && old_details.location() == kField && old_details.attributes() != new_attributes_) { + // Ensure we'll be updating constness of the up-to-date version of old_map_. + Handle old_map = Map::Update(isolate_, old_map_); + PropertyDetails details = + old_map->instance_descriptors(kRelaxedLoad).GetDetails(descriptor); Handle field_type( - old_descriptors_->GetFieldType(modified_descriptor_), isolate_); - Map::GeneralizeField(isolate_, old_map_, descriptor, - PropertyConstness::kMutable, - old_details.representation(), field_type); + old_map->instance_descriptors(kRelaxedLoad).GetFieldType(descriptor), + isolate_); + Map::GeneralizeField(isolate_, old_map, descriptor, + PropertyConstness::kMutable, details.representation(), + field_type); + DCHECK_EQ(PropertyConstness::kMutable, + old_map->instance_descriptors(kRelaxedLoad) + .GetDetails(descriptor) + .constness()); // The old_map_'s property must become mutable. // Note, that the {old_map_} and {old_descriptors_} are not expected to be // updated by the generalization if the map is already deprecated. diff --git a/deps/v8/test/mjsunit/compiler/regress-1195777.js b/deps/v8/test/mjsunit/compiler/regress-1195777.js new file mode 100644 index 00000000000000..b122f4f0169af5 --- /dev/null +++ b/deps/v8/test/mjsunit/compiler/regress-1195777.js @@ -0,0 +1,62 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + + +(function() { + function foo(b) { + let y = (new Date(42)).getMilliseconds(); + let x = -1; + if (b) x = 0xFFFF_FFFF; + return y < Math.max(1 << y, x, 1 + y); + } + assertTrue(foo(true)); + %PrepareFunctionForOptimization(foo); + assertTrue(foo(false)); + %OptimizeFunctionOnNextCall(foo); + assertTrue(foo(true)); +})(); + + +(function() { + function foo(b) { + let x = 0; + if (b) x = -1; + return x == Math.max(-1, x >>> Infinity); + } + assertFalse(foo(true)); + %PrepareFunctionForOptimization(foo); + assertTrue(foo(false)); + %OptimizeFunctionOnNextCall(foo); + assertFalse(foo(true)); +})(); + + +(function() { + function foo(b) { + let x = -1; + if (b) x = 0xFFFF_FFFF; + return -1 < Math.max(0, x, -1); + } + assertTrue(foo(true)); + %PrepareFunctionForOptimization(foo); + assertTrue(foo(false)); + %OptimizeFunctionOnNextCall(foo); + assertTrue(foo(true)); +})(); + + +(function() { + function foo(b) { + let x = 0x7FFF_FFFF; + if (b) x = 0; + return 0 < (Math.max(-5 >>> x, -5) % -5); + } + assertTrue(foo(true)); + %PrepareFunctionForOptimization(foo); + assertTrue(foo(false)); + %OptimizeFunctionOnNextCall(foo); + assertTrue(foo(true)); +})(); diff --git a/deps/v8/test/mjsunit/regress/regress-crbug-1195331.js b/deps/v8/test/mjsunit/regress/regress-crbug-1195331.js new file mode 100644 index 00000000000000..1bced5623e4f9a --- /dev/null +++ b/deps/v8/test/mjsunit/regress/regress-crbug-1195331.js @@ -0,0 +1,36 @@ +// Copyright 2021 the V8 project authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Flags: --allow-natives-syntax + +let o1 = { a: 1, b: 0 }; +let o2 = { a: 2, b: 0 }; +assertTrue(%HaveSameMap(o1, o2)); +assertTrue(%HasOwnConstDataProperty(o1, "a")); +assertTrue(%HasOwnConstDataProperty(o1, "b")); + +Object.defineProperty(o1, "b", { + value: 4.2, enumerable: true, configurable: true, writable: true, +}); +assertFalse(%HaveSameMap(o1, o2)); +assertTrue(%HasOwnConstDataProperty(o1, "a")); +assertFalse(%HasOwnConstDataProperty(o1, "b")); +assertTrue(%HasOwnConstDataProperty(o2, "a")); +assertTrue(%HasOwnConstDataProperty(o2, "b")); + +let o3 = { a: "foo", b: 0 }; +assertFalse(%HaveSameMap(o2, o3)); +assertTrue(%HasOwnConstDataProperty(o3, "a")); +assertFalse(%HasOwnConstDataProperty(o3, "b")); + +Object.defineProperty(o2, "a", { + value:2, enumerable: false, configurable: true, writable: true, +}); +assertFalse(%HasOwnConstDataProperty(o1, "a")); +assertFalse(%HasOwnConstDataProperty(o1, "b")); +assertFalse(%HasOwnConstDataProperty(o3, "a")); +assertFalse(%HasOwnConstDataProperty(o3, "b")); + +assertFalse(%HasOwnConstDataProperty(o2, "a")); +assertTrue(%HasOwnConstDataProperty(o2, "b")); From d3bd4b4771e9f9a72cabac0606161c002a049883 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Sun, 18 Apr 2021 19:21:22 -0400 Subject: [PATCH 004/110] tools: fix type mismatch in test runner `output.diagnostic` is a list that is appended to on SmartOS when retrying a test due to `ECONNREFUSED`. The test runner checks if `output.diagnostic` is truthy and, if so, assigns its value to `self.traceback`. However `self.traceback` is supposed to be a string, and `_printDiagnostic()` in the `TapProgressIndicator` attempts to call `splitlines()` on it, which fails if it is a list with: AttributeError: 'list' object has no attribute 'splitlines' PR-URL: https://github.com/nodejs/node/pull/38289 Reviewed-By: Rich Trott Reviewed-By: Christian Clauss Reviewed-By: Luigi Pinca Reviewed-By: Benjamin Gruenbaum --- tools/test.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/test.py b/tools/test.py index cdeb40d59cda78..c3a7ff07e23b5d 100755 --- a/tools/test.py +++ b/tools/test.py @@ -375,7 +375,10 @@ def HasRun(self, output): if output.diagnostic: self.severity = 'ok' - self.traceback = output.diagnostic + if isinstance(output.diagnostic, list): + self.traceback = '\n'.join(output.diagnostic) + else: + self.traceback = output.diagnostic duration = output.test.duration From eb8f5ce44f63a14484f3afccd328ba8208708788 Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Sun, 18 Apr 2021 15:32:12 -0400 Subject: [PATCH 005/110] test: use .test domain for not found address While it is extremely unlikely that `.fhqwhgads` will become a valid domain, we should, where possible, use one of the reserved domains for testing. Refs: https://tools.ietf.org/html/rfc2606 PR-URL: https://github.com/nodejs/node/pull/38286 Refs: https://github.com/nodejs/node/pull/38282 Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Luigi Pinca --- test/common/internet.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/common/internet.js b/test/common/internet.js index 1c53587fb6dbf7..accea74969e276 100644 --- a/test/common/internet.js +++ b/test/common/internet.js @@ -24,7 +24,7 @@ const addresses = { MX_HOST: 'nodejs.org', // On some systems, .invalid returns a server failure/try again rather than // record not found. Use this to guarantee record not found. - NOT_FOUND: 'come.on.fhqwhgads', + NOT_FOUND: 'come.on.fhqwhgads.test', // A host with SRV records registered SRV_HOST: '_jabber._tcp.google.com', // A host with PTR records registered From 2eef5876745740b923f5c011196f518c1d6febd9 Mon Sep 17 00:00:00 2001 From: Voltrex <62040526+VoltrexMaster@users.noreply.github.com> Date: Fri, 2 Apr 2021 04:25:38 +0430 Subject: [PATCH 006/110] doc: use `foo.prototype.bar` notation in buffer.md Most of the documentation uses `foo.prototype.bar` notation instead of `foo#bar` notation, this commit apply the former in `buffer.md`. PR-URL: https://github.com/nodejs/node/pull/38032 Reviewed-By: Derek Lewis Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: Darshan Sen --- doc/api/buffer.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 7e75e33a270a52..6e601dbf470278 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -176,12 +176,12 @@ however, subtle incompatibilities between the `Buffer` API and the In particular: -* While [`TypedArray#slice()`][] creates a copy of part of the `TypedArray`, - [`Buffer#slice()`][`buf.slice()`] creates a view over the existing `Buffer` +* While [`TypedArray.prototype.slice()`][] creates a copy of part of the `TypedArray`, + [`Buffer.prototype.slice()`][`buf.slice()`] creates a view over the existing `Buffer` without copying. This behavior can be surprising, and only exists for legacy - compatibility. [`TypedArray#subarray()`][] can be used to achieve the behavior - of [`Buffer#slice()`][`buf.slice()`] on both `Buffer`s and other - `TypedArray`s. + compatibility. [`TypedArray.prototype.subarray()`][] can be used to achieve + the behavior of [`Buffer.prototype.slice()`][`buf.slice()`] on both `Buffer`s + and other `TypedArray`s. * [`buf.toString()`][] is incompatible with its `TypedArray` equivalent. * A number of methods, e.g. [`buf.indexOf()`][], support additional arguments. @@ -1086,9 +1086,9 @@ added: v0.1.90 Copies data from a region of `buf` to a region in `target`, even if the `target` memory region overlaps with `buf`. -[`TypedArray#set()`][] performs the same operation, and is available for all -TypedArrays, including Node.js `Buffer`s, although it takes different -function arguments. +[`TypedArray.prototype.set()`][] performs the same operation, and is available +for all TypedArrays, including Node.js `Buffer`s, although it takes +different function arguments. ```js // Create two `Buffer` instances. @@ -1349,7 +1349,7 @@ an integer between 0 and 255. If `byteOffset` is not a number, it will be coerced to a number. If the result of coercion is `NaN` or `0`, then the entire buffer will be searched. This -behavior matches [`String#indexOf()`][]. +behavior matches [`String.prototype.indexOf()`][]. ```js const b = Buffer.from('abcdef'); @@ -1449,7 +1449,7 @@ an integer between 0 and 255. If `byteOffset` is not a number, it will be coerced to a number. Any arguments that coerce to `NaN`, like `{}` or `undefined`, will search the whole buffer. -This behavior matches [`String#lastIndexOf()`][]. +This behavior matches [`String.prototype.lastIndexOf()`][]. ```js const b = Buffer.from('abcdef'); @@ -2136,7 +2136,7 @@ offset and cropped by the `start` and `end` indices. Specifying `end` greater than [`buf.length`][] will return the same result as that of `end` equal to [`buf.length`][]. -This method is inherited from [`TypedArray#subarray()`][]. +This method is inherited from [`TypedArray.prototype.subarray()`][]. Modifying the new `Buffer` slice will modify the memory in the original `Buffer` because the allocated memory of the two objects overlap. @@ -3574,13 +3574,13 @@ introducing security vulnerabilities into an application. [`ERR_OUT_OF_RANGE`]: errors.md#ERR_OUT_OF_RANGE [`JSON.stringify()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify [`SharedArrayBuffer`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/SharedArrayBuffer -[`String#indexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf -[`String#lastIndexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf +[`String.prototype.indexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf +[`String.prototype.lastIndexOf()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf [`String.prototype.length`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length -[`TypedArray#set()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set -[`TypedArray#slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice -[`TypedArray#subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray [`TypedArray.from()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/from +[`TypedArray.prototype.set()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/set +[`TypedArray.prototype.slice()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/slice +[`TypedArray.prototype.subarray()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray/subarray [`TypedArray`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray [`Uint8Array`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Uint8Array [`buf.buffer`]: #buffer_buf_buffer From f6745e937046df78dde441e4ea084aeb604a3d6a Mon Sep 17 00:00:00 2001 From: eladkeyshawn Date: Fri, 9 Apr 2021 20:12:59 +0300 Subject: [PATCH 007/110] tls: fix `tlsSocket.setMaxSendFragment` abort PR-URL: https://github.com/nodejs/node/pull/38170 Fixes: https://github.com/nodejs/node/issues/38169 Reviewed-By: Benjamin Gruenbaum Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- lib/_tls_wrap.js | 4 ++- test/parallel/test-tls-max-send-fragment.js | 27 +++++++++++++++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index 9ecd92021de17f..a54bd0d0d35777 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -86,9 +86,10 @@ const { const { validateBuffer, validateCallback, + validateInt32, validateObject, validateString, - validateUint32 + validateUint32, } = require('internal/validators'); const { InternalX509Certificate @@ -893,6 +894,7 @@ TLSSocket.prototype.exportKeyingMaterial = function(length, label, context) { }; TLSSocket.prototype.setMaxSendFragment = function setMaxSendFragment(size) { + validateInt32(size, 'size'); return this._handle.setMaxSendFragment(size) === 1; }; diff --git a/test/parallel/test-tls-max-send-fragment.js b/test/parallel/test-tls-max-send-fragment.js index eca995d66483b5..bbb7849f005bf9 100644 --- a/test/parallel/test-tls-max-send-fragment.js +++ b/test/parallel/test-tls-max-send-fragment.js @@ -33,15 +33,38 @@ const buf = Buffer.allocUnsafe(10000); let received = 0; const maxChunk = 768; +const invalidArgumentError = { + name: 'TypeError', + code: 'ERR_INVALID_ARG_TYPE' +}; + const server = tls.createServer({ key: fixtures.readKey('agent1-key.pem'), cert: fixtures.readKey('agent1-cert.pem') }, function(c) { - // Lower and upper limits + + // No size is passed. + assert.throws(() => c.setMaxSendFragment(), invalidArgumentError); + + // Invalid arg is passed. + [null, undefined, '', {}, false, true, []].forEach((arg) => { + assert.throws(() => c.setMaxSendFragment(arg), invalidArgumentError); + }); + + [NaN, Infinity, 2 ** 31].forEach((arg) => { + assert.throws(() => c.setMaxSendFragment(arg), { + name: 'RangeError', + code: 'ERR_OUT_OF_RANGE' + }); + }); + + assert.throws(() => c.setMaxSendFragment(Symbol()), { name: 'TypeError' }); + + // Lower and upper limits. assert(!c.setMaxSendFragment(511)); assert(!c.setMaxSendFragment(16385)); - // Correct fragment size + // Correct fragment size. assert(c.setMaxSendFragment(maxChunk)); c.end(buf); From bc6e719884188a186cb882d694bf86d50b2ba9fb Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Mon, 12 Apr 2021 17:36:24 +0200 Subject: [PATCH 008/110] bootstrap: freeze more intrinsics PR-URL: https://github.com/nodejs/node/pull/38217 Reviewed-By: Guy Bedford --- lib/internal/freeze_intrinsics.js | 240 +++++++++++++----------- test/parallel/test-freeze-intrinsics.js | 7 + 2 files changed, 141 insertions(+), 106 deletions(-) diff --git a/lib/internal/freeze_intrinsics.js b/lib/internal/freeze_intrinsics.js index e7282588551929..ca73559c3eb0cf 100644 --- a/lib/internal/freeze_intrinsics.js +++ b/lib/internal/freeze_intrinsics.js @@ -23,9 +23,12 @@ 'use strict'; const { + AggregateError, + AggregateErrorPrototype, Array, ArrayBuffer, ArrayBufferPrototype, + ArrayIteratorPrototype, ArrayPrototype, ArrayPrototypeForEach, ArrayPrototypePush, @@ -45,6 +48,8 @@ const { ErrorPrototype, EvalError, EvalErrorPrototype, + FinalizationRegistry, + FinalizationRegistryPrototype, Float32Array, Float32ArrayPrototype, Float64Array, @@ -84,9 +89,12 @@ const { Set, SetPrototype, String, + StringIteratorPrototype, StringPrototype, Symbol, SymbolIterator, + SymbolMatchAll, + SymbolPrototype, SyntaxError, SyntaxErrorPrototype, TypeError, @@ -105,12 +113,15 @@ const { URIErrorPrototype, WeakMap, WeakMapPrototype, + WeakRef, + WeakRefPrototype, WeakSet, WeakSetPrototype, decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, + globalThis, } = primordials; module.exports = function() { @@ -124,34 +135,14 @@ module.exports = function() { } = require('timers'); const intrinsicPrototypes = [ - // Anonymous Intrinsics - // IteratorPrototype - ObjectGetPrototypeOf( - ObjectGetPrototypeOf(new Array()[SymbolIterator]()) - ), - // ArrayIteratorPrototype - ObjectGetPrototypeOf(new Array()[SymbolIterator]()), - // StringIteratorPrototype - ObjectGetPrototypeOf(new String()[SymbolIterator]()), - // MapIteratorPrototype - ObjectGetPrototypeOf(new Map()[SymbolIterator]()), - // SetIteratorPrototype - ObjectGetPrototypeOf(new Set()[SymbolIterator]()), - // GeneratorFunction - ObjectGetPrototypeOf(function* () {}), - // AsyncFunction - ObjectGetPrototypeOf(async function() {}), - // AsyncGeneratorFunction - ObjectGetPrototypeOf(async function* () {}), - // TypedArray - TypedArrayPrototype, - - // 19 Fundamental Objects - ObjectPrototype, // 19.1 - FunctionPrototype, // 19.2 - BooleanPrototype, // 19.3 - - ErrorPrototype, // 19.5 + // 20 Fundamental Objects + ObjectPrototype, // 20.1 + FunctionPrototype, // 20.2 + BooleanPrototype, // 20.3 + SymbolPrototype, // 20.4 + + ErrorPrototype, // 20.5 + AggregateErrorPrototype, EvalErrorPrototype, RangeErrorPrototype, ReferenceErrorPrototype, @@ -159,17 +150,23 @@ module.exports = function() { TypeErrorPrototype, URIErrorPrototype, - // 20 Numbers and Dates - NumberPrototype, // 20.1 - DatePrototype, // 20.3 + // 21 Numbers and Dates + NumberPrototype, // 21.1 + BigIntPrototype, // 21.2 + DatePrototype, // 21.4 - // 21 Text Processing - StringPrototype, // 21.1 - RegExpPrototype, // 21.2 + // 22 Text Processing + StringPrototype, // 22.1 + StringIteratorPrototype, // 22.1.5 + RegExpPrototype, // 22.2 + // 22.2.7 RegExpStringIteratorPrototype + ObjectGetPrototypeOf(/e/[SymbolMatchAll]()), - // 22 Indexed Collections - ArrayPrototype, // 22.1 + // 23 Indexed Collections + ArrayPrototype, // 23.1 + ArrayIteratorPrototype, // 23.1.5 + TypedArrayPrototype, // 23.2 Int8ArrayPrototype, Uint8ArrayPrototype, Uint8ClampedArrayPrototype, @@ -182,20 +179,36 @@ module.exports = function() { BigInt64ArrayPrototype, BigUint64ArrayPrototype, - // 23 Keyed Collections - MapPrototype, // 23.1 - SetPrototype, // 23.2 - WeakMapPrototype, // 23.3 - WeakSetPrototype, // 23.4 - - // 24 Structured Data - ArrayBufferPrototype, // 24.1 - DataViewPrototype, // 24.3 - PromisePrototype, // 25.4 + // 24 Keyed Collections + MapPrototype, // 24.1 + // 24.1.5 MapIteratorPrototype + ObjectGetPrototypeOf(new Map()[SymbolIterator]()), + SetPrototype, // 24.2 + // 24.2.5 SetIteratorPrototype + ObjectGetPrototypeOf(new Set()[SymbolIterator]()), + WeakMapPrototype, // 24.3 + WeakSetPrototype, // 24.4 + + // 25 Structured Data + ArrayBufferPrototype, // 25.1 + SharedArrayBuffer.prototype, // 25.2 + DataViewPrototype, // 25.3 + + // 26 Managing Memory + WeakRefPrototype, // 26.1 + FinalizationRegistryPrototype, // 26.2 + + // 27 Control Abstraction Objects + // 27.1 Iteration + ObjectGetPrototypeOf(ArrayIteratorPrototype), // 27.1.2 IteratorPrototype + // 27.1.3 AsyncIteratorPrototype + ObjectGetPrototypeOf(ObjectGetPrototypeOf(ObjectGetPrototypeOf( + (async function*() {})() + ))), + PromisePrototype, // 27.2 // Other APIs / Web Compatibility console.Console.prototype, - BigIntPrototype, WebAssembly.Module.prototype, WebAssembly.Instance.prototype, WebAssembly.Table.prototype, @@ -203,34 +216,13 @@ module.exports = function() { WebAssembly.CompileError.prototype, WebAssembly.LinkError.prototype, WebAssembly.RuntimeError.prototype, - SharedArrayBuffer.prototype, ]; const intrinsics = [ - // Anonymous Intrinsics - // ThrowTypeError + // 10.2.4.1 ThrowTypeError ObjectGetOwnPropertyDescriptor(FunctionPrototype, 'caller').get, - // IteratorPrototype - ObjectGetPrototypeOf( - ObjectGetPrototypeOf(new Array()[SymbolIterator]()) - ), - // ArrayIteratorPrototype - ObjectGetPrototypeOf(new Array()[SymbolIterator]()), - // StringIteratorPrototype - ObjectGetPrototypeOf(new String()[SymbolIterator]()), - // MapIteratorPrototype - ObjectGetPrototypeOf(new Map()[SymbolIterator]()), - // SetIteratorPrototype - ObjectGetPrototypeOf(new Set()[SymbolIterator]()), - // GeneratorFunction - ObjectGetPrototypeOf(function* () {}), - // AsyncFunction - ObjectGetPrototypeOf(async function() {}), - // AsyncGeneratorFunction - ObjectGetPrototypeOf(async function* () {}), - // TypedArray - TypedArray, - // 18 The Global Object + // 19 The Global Object + // 19.2 Function Properties of the Global Object eval, // eslint-disable-next-line node-core/prefer-primordials isFinite, @@ -240,18 +232,20 @@ module.exports = function() { parseFloat, // eslint-disable-next-line node-core/prefer-primordials parseInt, + // 19.2.6 URI Handling Functions decodeURI, decodeURIComponent, encodeURI, encodeURIComponent, - // 19 Fundamental Objects - Object, // 19.1 - Function, // 19.2 - Boolean, // 19.3 - Symbol, // 19.4 + // 20 Fundamental Objects + Object, // 20.1 + Function, // 20.2 + Boolean, // 20.3 + Symbol, // 20.4 - Error, // 19.5 + Error, // 20.5 + AggregateError, EvalError, RangeError, ReferenceError, @@ -259,19 +253,25 @@ module.exports = function() { TypeError, URIError, - // 20 Numbers and Dates - Number, // 20.1 + // 21 Numbers and Dates + Number, // 21.1 + BigInt, // 21.2 // eslint-disable-next-line node-core/prefer-primordials - Math, // 20.2 - Date, // 20.3 - - // 21 Text Processing - String, // 21.1 - RegExp, // 21.2 - - // 22 Indexed Collections - Array, // 22.1 - + Math, // 21.3 + Date, // 21.4 + + // 22 Text Processing + String, // 22.1 + StringIteratorPrototype, // 22.1.5 + RegExp, // 22.2 + // 22.2.7 RegExpStringIteratorPrototype + ObjectGetPrototypeOf(/e/[SymbolMatchAll]()), + + // 23 Indexed Collections + Array, // 23.1 + ArrayIteratorPrototype, // 23.1.5 + // 23.2 TypedArray + TypedArray, Int8Array, Uint8Array, Uint8ClampedArray, @@ -284,23 +284,47 @@ module.exports = function() { BigInt64Array, BigUint64Array, - // 23 Keyed Collections - Map, // 23.1 - Set, // 23.2 - WeakMap, // 23.3 - WeakSet, // 23.4 - - // 24 Structured Data - ArrayBuffer, // 24.1 - DataView, // 24.3 + // 24 Keyed Collections + Map, // 24.1 + // 24.1.5 MapIteratorPrototype + ObjectGetPrototypeOf(new Map()[SymbolIterator]()), + Set, // 24.2 + // 24.2.5 SetIteratorPrototype + ObjectGetPrototypeOf(new Set()[SymbolIterator]()), + WeakMap, // 24.3 + WeakSet, // 24.4 + + // 25 Structured Data + ArrayBuffer, // 25.1 + SharedArrayBuffer, // 25.2 + DataView, // 25.3 + Atomics, // 25.4 // eslint-disable-next-line node-core/prefer-primordials - JSON, // 24.5 - Promise, // 25.4 + JSON, // 25.5 + + // 26 Managing Memory + WeakRef, // 26.1 + FinalizationRegistry, // 26.2 + + // 27 Control Abstraction Objects + // 27.1 Iteration + ObjectGetPrototypeOf(ArrayIteratorPrototype), // 27.1.2 IteratorPrototype + // 27.1.3 AsyncIteratorPrototype + ObjectGetPrototypeOf(ObjectGetPrototypeOf(ObjectGetPrototypeOf( + (async function*() {})() + ))), + Promise, // 27.2 + // 27.3 GeneratorFunction + ObjectGetPrototypeOf(function* () {}), + // 27.4 AsyncGeneratorFunction + ObjectGetPrototypeOf(async function* () {}), + // 27.7 AsyncFunction + ObjectGetPrototypeOf(async function() {}), - // 26 Reflection + // 28 Reflection // eslint-disable-next-line node-core/prefer-primordials - Reflect, // 26.1 - Proxy, // 26.2 + Reflect, // 28.1 + Proxy, // 28.2 // B.2.1 escape, @@ -314,10 +338,7 @@ module.exports = function() { setInterval, setTimeout, console, - BigInt, - Atomics, WebAssembly, - SharedArrayBuffer, ]; if (typeof Intl !== 'undefined') { @@ -337,6 +358,13 @@ module.exports = function() { const frozenSet = new WeakSet(); ArrayPrototypeForEach(intrinsics, deepFreeze); + // 19.1 Value Properties of the Global Object + ObjectDefineProperty(globalThis, 'globalThis', { + configurable: false, + writable: false, + value: globalThis, + }); + // Objects that are deeply frozen. function deepFreeze(root) { /** diff --git a/test/parallel/test-freeze-intrinsics.js b/test/parallel/test-freeze-intrinsics.js index 2e9ff5f4fe2fdc..978a6861a517fc 100644 --- a/test/parallel/test-freeze-intrinsics.js +++ b/test/parallel/test-freeze-intrinsics.js @@ -30,3 +30,10 @@ assert.throws( assert.strictEqual(Object.getOwnPropertyDescriptor(o, 'toString').enumerable, true); } + +// Ensure we can not override globalThis +{ + assert.throws(() => { globalThis.globalThis = null; }, + { name: 'TypeError' }); + assert.strictEqual(globalThis.globalThis, globalThis); +} From 8a90f55a056c3c260a030f71bfee664130f30365 Mon Sep 17 00:00:00 2001 From: Nitzan Uziely Date: Sun, 18 Apr 2021 22:40:59 +0300 Subject: [PATCH 009/110] fs: allow no-params fsPromises fileHandle read allow no-params read for fsPromises fileHandle read PR-URL: https://github.com/nodejs/node/pull/38287 Reviewed-By: Anna Henningsen Reviewed-By: Antoine du Hamel Reviewed-By: Colin Ihrig Reviewed-By: Rich Trott Reviewed-By: Darshan Sen Reviewed-By: Luigi Pinca --- doc/api/fs.md | 2 +- lib/internal/fs/promises.js | 3 +++ test/parallel/test-fs-promises-file-handle-read.js | 8 ++++++++ 3 files changed, 12 insertions(+), 1 deletion(-) diff --git a/doc/api/fs.md b/doc/api/fs.md index 9190d41b218fc9..179cabbfff5113 100644 --- a/doc/api/fs.md +++ b/doc/api/fs.md @@ -285,7 +285,7 @@ Reads data from the file and stores that in the given buffer. If the file is not modified concurrently, the end-of-file is reached when the number of bytes read is zero. -#### `filehandle.read(options)` +#### `filehandle.read([options])` +* [aduh95](https://github.com/aduh95) - +**Antoine du Hamel** <duhamelantoine1995@gmail.com> (he/him) * [apapirovski](https://github.com/apapirovski) - **Anatoli Papirovski** <apapirovski@mac.com> (he/him) * [BethGriggs](https://github.com/BethGriggs) - @@ -169,6 +171,8 @@ For information about the governance of the Node.js project, see **Shelley Vohr** <codebytere@gmail.com> (she/her) * [danbev](https://github.com/danbev) - **Daniel Bevenius** <daniel.bevenius@gmail.com> (he/him) +* [danielleadams](https://github.com/danielleadams) - +**Danielle Adams** <adamzdanielle@gmail.com> (she/her) * [fhinkel](https://github.com/fhinkel) - **Franziska Hinkelmann** <franziska.hinkelmann@gmail.com> (she/her) * [gabrielschulhof](https://github.com/gabrielschulhof) - @@ -187,6 +191,8 @@ For information about the governance of the Node.js project, see **Mary Marchini** <oss@mmarchini.me> (she/her) * [MylesBorins](https://github.com/MylesBorins) - **Myles Borins** <myles.borins@gmail.com> (he/him) +* [ronag](https://github.com/ronag) - +**Robert Nagy** <ronagy@icloud.com> * [targos](https://github.com/targos) - **Michaël Zasso** <targos@protonmail.com> (he/him) * [tniessen](https://github.com/tniessen) - From 25052dc987cb4b7bfa9f1585eb4a362b882e8658 Mon Sep 17 00:00:00 2001 From: Daniel Bevenius Date: Mon, 19 Apr 2021 05:50:21 +0200 Subject: [PATCH 013/110] doc: add nodejs-sec email template This commit adds a suggestion for a template to be used as part of the security release process. One step of this process is to create an email to nodejs-sec group and currently would contain a copy and pasted version of what is published on nodejs.org. This suggestion is to instead use a link to the blog post. PR-URL: https://github.com/nodejs/node/pull/38290 Refs: https://github.com/nodejs/node/issues/38143 Reviewed-By: Michael Dawson Reviewed-By: James M Snell --- doc/guides/security-release-process.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/doc/guides/security-release-process.md b/doc/guides/security-release-process.md index 5609e40739d3fb..10465c57501328 100644 --- a/doc/guides/security-release-process.md +++ b/doc/guides/security-release-process.md @@ -38,6 +38,12 @@ information described. * Described in the pre/post announcements * [ ] Pre-release announcement [email][]: ***LINK TO EMAIL*** + ```text + Security updates for all active release lines, Month Year + + The Node.js project will release new versions of all supported release lines on or shortly after Day of week, Month Day of Month, Year + For more information see: https://nodejs.org/en/blog/vulnerability/month-year-security-releases/ + ``` (Get access from existing manager: Ben Noordhuis, Rod Vagg, Michael Dawson) * [ ] Pre-release announcement to nodejs.org blog: ***LINK TO BLOG*** @@ -64,6 +70,12 @@ information described. * [ ] [Unlock CI](https://github.com/nodejs/build/blob/HEAD/doc/jenkins-guide.md#after-the-release) * [ ] Post-release announcement in reply [email][]: ***LINK TO EMAIL*** + ```text + Security updates for all active release lines, Month Year + + The Node.js project has now released new versions of all supported release lines. + For more information see: https://nodejs.org/en/blog/vulnerability/month-year-security-releases/ + ``` * [ ] Post-release announcement to Nodejs.org blog: ***LINK TO BLOG POST*** * (Re-PR the pre-approved branch from nodejs-private/nodejs.org-private to From 1cccc2da51fcff254950c5c93047a37d01311b49 Mon Sep 17 00:00:00 2001 From: Jayden Seric Date: Wed, 21 Apr 2021 10:54:38 +1000 Subject: [PATCH 014/110] doc: fix YAML comment opening tags Several YAML documentation comments incorrectly started with ` @@ -455,7 +455,7 @@ can be written: ``` ### Conditional exports - From 5b393d9258c5f2904fa20baec9c2cf444e50de78 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Tue, 20 Apr 2021 11:59:02 +0200 Subject: [PATCH 015/110] tls: validate ticket keys buffer Fixes: https://github.com/nodejs/node/issues/38305 PR-URL: https://github.com/nodejs/node/pull/38308 Reviewed-By: Darshan Sen Reviewed-By: Luigi Pinca Reviewed-By: James M Snell --- doc/api/tls.md | 3 ++- lib/_tls_wrap.js | 3 +++ test/parallel/test-tls-ticket-invalid-arg.js | 24 ++++++++++++++++++++ 3 files changed, 29 insertions(+), 1 deletion(-) create mode 100644 test/parallel/test-tls-ticket-invalid-arg.js diff --git a/doc/api/tls.md b/doc/api/tls.md index 0b8795661b1002..432ffff8675c8e 100644 --- a/doc/api/tls.md +++ b/doc/api/tls.md @@ -730,7 +730,8 @@ existing server. Existing connections to the server are not interrupted. added: v3.0.0 --> -* `keys` {Buffer} A 48-byte buffer containing the session ticket keys. +* `keys` {Buffer|TypedArray|DataView} A 48-byte buffer containing the session + ticket keys. Sets the session ticket keys. diff --git a/lib/_tls_wrap.js b/lib/_tls_wrap.js index a54bd0d0d35777..66ebc7b77869f7 100644 --- a/lib/_tls_wrap.js +++ b/lib/_tls_wrap.js @@ -1396,6 +1396,9 @@ Server.prototype.getTicketKeys = function getTicketKeys() { Server.prototype.setTicketKeys = function setTicketKeys(keys) { + validateBuffer(keys); + assert(keys.byteLength === 48, + 'Session ticket keys must be a 48-byte buffer'); this._sharedCreds.context.setTicketKeys(keys); }; diff --git a/test/parallel/test-tls-ticket-invalid-arg.js b/test/parallel/test-tls-ticket-invalid-arg.js new file mode 100644 index 00000000000000..55143cdca31e77 --- /dev/null +++ b/test/parallel/test-tls-ticket-invalid-arg.js @@ -0,0 +1,24 @@ +'use strict'; +const common = require('../common'); +if (!common.hasCrypto) { + common.skip('missing crypto'); +} + +const assert = require('assert'); +const tls = require('tls'); + +const server = new tls.Server(); + +[null, undefined, 0, 1, 1n, Symbol(), {}, [], true, false, '', () => {}] + .forEach((arg) => + assert.throws( + () => server.setTicketKeys(arg), + { code: 'ERR_INVALID_ARG_TYPE' } + )); + +[new Uint8Array(1), Buffer.from([1]), new DataView(new ArrayBuffer(2))].forEach( + (arg) => + assert.throws(() => { + server.setTicketKeys(arg); + }, /Session ticket keys must be a 48-byte buffer/) +); From 7354479ad5a7920055ab8a0d766a9cb6c23ae672 Mon Sep 17 00:00:00 2001 From: eladkeyshawn Date: Tue, 20 Apr 2021 14:28:20 +0300 Subject: [PATCH 016/110] crypto: fix DiffieHellman `generator` validation PR-URL: https://github.com/nodejs/node/pull/38311 Fixes: https://github.com/nodejs/node/issues/38302 Reviewed-By: Antoine du Hamel Reviewed-By: Luigi Pinca Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum Reviewed-By: Minwoo Jung Reviewed-By: Darshan Sen --- lib/internal/crypto/diffiehellman.js | 4 ++-- test/parallel/test-crypto-dh.js | 4 ++++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/internal/crypto/diffiehellman.js b/lib/internal/crypto/diffiehellman.js index e2106b211ba01b..2e38e95ea1d774 100644 --- a/lib/internal/crypto/diffiehellman.js +++ b/lib/internal/crypto/diffiehellman.js @@ -122,9 +122,9 @@ function DiffieHellman(sizeOrKey, keyEncoding, generator, genEncoding) { generator = DH_GENERATOR; } else if (typeof generator === 'number') { validateInt32(generator, 'generator'); - } else if (generator !== true) { + } else if (typeof generator === 'string') { generator = toBuf(generator, genEncoding); - } else { + } else if (!isArrayBufferView(generator) && !isAnyArrayBuffer(generator)) { throw new ERR_INVALID_ARG_TYPE( 'generator', ['number', 'string', 'ArrayBuffer', 'Buffer', 'TypedArray', 'DataView'], diff --git a/test/parallel/test-crypto-dh.js b/test/parallel/test-crypto-dh.js index e35585e8eb19d1..cae9301517c37c 100644 --- a/test/parallel/test-crypto-dh.js +++ b/test/parallel/test-crypto-dh.js @@ -495,3 +495,7 @@ assert.throws( code: 'ERR_INVALID_ARG_TYPE' } ); +[true, Symbol(), {}, () => {}, []].forEach((generator) => assert.throws( + () => crypto.createDiffieHellman('', 'base64', generator), + { code: 'ERR_INVALID_ARG_TYPE' } +)); From 0e88ae7ec1bce50c57ced2360cd87c69c5ac2d83 Mon Sep 17 00:00:00 2001 From: divlo Date: Wed, 21 Apr 2021 03:13:09 +0200 Subject: [PATCH 017/110] doc: fix typo in buffer.md 'uint16arr' -> 'uint16array' PR-URL: https://github.com/nodejs/node/pull/38323 Reviewed-By: Luigi Pinca Reviewed-By: Darshan Sen --- doc/api/buffer.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/api/buffer.md b/doc/api/buffer.md index 6e601dbf470278..3c8dc975e4248b 100644 --- a/doc/api/buffer.md +++ b/doc/api/buffer.md @@ -205,7 +205,7 @@ console.log(uint32array); ```js const buf = Buffer.from('hello', 'utf16le'); -const uint16arr = new Uint16Array( +const uint16array = new Uint16Array( buf.buffer, buf.byteOffset, buf.length / Uint16Array.BYTES_PER_ELEMENT); From 27d7588ad560f7addfbb0a617d838c666dccf6ac Mon Sep 17 00:00:00 2001 From: Richard Lau Date: Sun, 18 Apr 2021 14:56:24 -0400 Subject: [PATCH 018/110] test: add ancestor package.json checks for tmpdir Policy tests can fail if a `package.json` exists in any of the parent directories above the test. The existing checks are done for the ancestors of the test directory but some tests execute from the tmpdir. PR-URL: https://github.com/nodejs/node/pull/38285 Refs: https://github.com/nodejs/node/issues/38088 Refs: https://github.com/nodejs/node/issues/35600 Refs: https://github.com/nodejs/node/pull/35633 Reviewed-By: Rich Trott Reviewed-By: Colin Ihrig Reviewed-By: James M Snell --- test/common/README.md | 8 +++++--- test/common/index.js | 4 ++-- test/pummel/test-policy-integrity.js | 1 + 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/test/common/README.md b/test/common/README.md index 2f2ee17a0f01e4..29f073b28842a7 100644 --- a/test/common/README.md +++ b/test/common/README.md @@ -370,10 +370,12 @@ const { spawn } = require('child_process'); spawn(...common.pwdCommand, { stdio: ['pipe'] }); ``` -### `requireNoPackageJSONAbove()` +### `requireNoPackageJSONAbove([dir])` -Throws an `AssertionError` if a `package.json` file is in any ancestor -directory. Such files may interfere with proper test functionality. +* `dir` [<string>][] default = \_\_dirname + +Throws an `AssertionError` if a `package.json` file exists in any ancestor +directory above `dir`. Such files may interfere with proper test functionality. ### `runWithInvalidFD(func)` diff --git a/test/common/index.js b/test/common/index.js index f0d8c72d4a1017..f40914c94928dd 100644 --- a/test/common/index.js +++ b/test/common/index.js @@ -708,8 +708,8 @@ function gcUntil(name, condition) { }); } -function requireNoPackageJSONAbove() { - let possiblePackage = path.join(__dirname, '..', 'package.json'); +function requireNoPackageJSONAbove(dir = __dirname) { + let possiblePackage = path.join(dir, '..', 'package.json'); let lastPackage = null; while (possiblePackage !== lastPackage) { if (fs.existsSync(possiblePackage)) { diff --git a/test/pummel/test-policy-integrity.js b/test/pummel/test-policy-integrity.js index 15124aefd46904..c29bb7a7b3f90e 100644 --- a/test/pummel/test-policy-integrity.js +++ b/test/pummel/test-policy-integrity.js @@ -76,6 +76,7 @@ function newTestId() { return nextTestId++; } tmpdir.refresh(); +common.requireNoPackageJSONAbove(tmpdir.path); let spawned = 0; const toSpawn = []; From 3649ec527648ae15d2b6b979270df620879c30c3 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 21 Apr 2021 16:38:28 -0700 Subject: [PATCH 019/110] src: avoid deferred gc/cleanup for Buffer.from Previously, the code path would allocated a tracked ArrayBuffer that defers cleanup and deallocation of the underlying data with a SetImmediate. Avoid the unnecessary deferral by just allocating a `BackingStore` directly and writing into it. Fixes: https://github.com/nodejs/node/issues/38300 Refs: https://github.com/nodejs/node/pull/38336 PR-URL: https://github.com/nodejs/node/pull/38337 Reviewed-By: Anna Henningsen Reviewed-By: Khaidi Chu Reviewed-By: Matteo Collina Reviewed-By: Joyee Cheung --- src/node_buffer.cc | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/src/node_buffer.cc b/src/node_buffer.cc index 485e273f2fbe9e..9006c1de767533 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -303,28 +303,36 @@ MaybeLocal New(Isolate* isolate, if (!StringBytes::Size(isolate, string, enc).To(&length)) return Local(); size_t actual = 0; - char* data = nullptr; + std::unique_ptr store; if (length > 0) { - data = UncheckedMalloc(length); + store = ArrayBuffer::NewBackingStore(isolate, length); - if (data == nullptr) { + if (UNLIKELY(!store)) { THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate); return Local(); } - actual = StringBytes::Write(isolate, data, length, string, enc); + actual = StringBytes::Write( + isolate, + static_cast(store->Data()), + length, + string, + enc); CHECK(actual <= length); - if (actual == 0) { - free(data); - data = nullptr; - } else if (actual < length) { - data = node::Realloc(data, actual); + if (LIKELY(actual > 0)) { + if (actual < length) + store = BackingStore::Reallocate(isolate, std::move(store), actual); + Local buf = ArrayBuffer::New(isolate, std::move(store)); + Local obj; + if (UNLIKELY(!New(isolate, buf, 0, actual).ToLocal(&obj))) + return MaybeLocal(); + return scope.Escape(obj); } } - return scope.EscapeMaybe(New(isolate, data, actual)); + return scope.EscapeMaybe(New(isolate, 0)); } From 09cacd74183968eeaf80fc5106dc7c4462b8e841 Mon Sep 17 00:00:00 2001 From: James M Snell Date: Wed, 21 Apr 2021 08:23:55 -0700 Subject: [PATCH 020/110] src: fix setting Converter sub char length MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: James M Snell Fixes: https://github.com/nodejs/node/issues/38330 PR-URL: https://github.com/nodejs/node/pull/38331 Reviewed-By: Juan José Arboleda Reviewed-By: Benjamin Gruenbaum --- src/node_i18n.cc | 14 ++++++++++++-- test/parallel/test-icu-transcode.js | 5 +++++ 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/node_i18n.cc b/src/node_i18n.cc index 48f95ceb68d9c1..42e618ac30181f 100644 --- a/src/node_i18n.cc +++ b/src/node_i18n.cc @@ -148,8 +148,13 @@ MaybeLocal Transcode(Environment* env, *status = U_ZERO_ERROR; MaybeLocal ret; MaybeStackBuffer result; - Converter to(toEncoding, "?"); + Converter to(toEncoding); Converter from(fromEncoding); + + size_t sublen = ucnv_getMinCharSize(to.conv()); + std::string sub(sublen, '?'); + to.set_subst_chars(sub.c_str()); + const uint32_t limit = source_length * to.max_char_size(); result.AllocateSufficientStorage(limit); char* target = *result; @@ -190,7 +195,12 @@ MaybeLocal TranscodeFromUcs2(Environment* env, *status = U_ZERO_ERROR; MaybeStackBuffer sourcebuf; MaybeLocal ret; - Converter to(toEncoding, "?"); + Converter to(toEncoding); + + size_t sublen = ucnv_getMinCharSize(to.conv()); + std::string sub(sublen, '?'); + to.set_subst_chars(sub.c_str()); + const size_t length_in_chars = source_length / sizeof(UChar); CopySourceBuffer(&sourcebuf, source, source_length, length_in_chars); MaybeStackBuffer destbuf(length_in_chars); diff --git a/test/parallel/test-icu-transcode.js b/test/parallel/test-icu-transcode.js index 20ecab7213b292..e9aced128eec21 100644 --- a/test/parallel/test-icu-transcode.js +++ b/test/parallel/test-icu-transcode.js @@ -83,3 +83,8 @@ assert.deepStrictEqual( const dest = buffer.transcode(new Uint8Array(), 'utf8', 'latin1'); assert.strictEqual(dest.length, 0); } + +// Test that it doesn't crash +{ + buffer.transcode(new buffer.SlowBuffer(1), 'utf16le', 'ucs2'); +} From e389e86b6b4721842c69fe60cf6305c469ccc0b7 Mon Sep 17 00:00:00 2001 From: Rohit Gohri Date: Mon, 12 Apr 2021 20:25:11 +0530 Subject: [PATCH 021/110] typings: add JSDoc typings for util PR-URL: https://github.com/nodejs/node/pull/38213 Refs: https://github.com/nodejs/node/pull/38182 Refs: https://twitter.com/bradleymeck/status/1380643627211354115 Reviewed-By: Bradley Farias Reviewed-By: Michael Dawson Reviewed-By: James M Snell --- lib/util.js | 92 ++++++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 88 insertions(+), 4 deletions(-) diff --git a/lib/util.js b/lib/util.js index f3c10bb7720e58..bcb1c81933c0c0 100644 --- a/lib/util.js +++ b/lib/util.js @@ -74,51 +74,109 @@ const { let internalDeepEqual; +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is boolean} + */ function isBoolean(arg) { return typeof arg === 'boolean'; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is null} + */ function isNull(arg) { return arg === null; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is (null | undefined)} + */ function isNullOrUndefined(arg) { return arg === null || arg === undefined; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is number} + */ function isNumber(arg) { return typeof arg === 'number'; } +/** + * @param {any} arg + * @returns {arg is string} + */ function isString(arg) { return typeof arg === 'string'; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is symbol} + */ function isSymbol(arg) { return typeof arg === 'symbol'; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is undefined} + */ function isUndefined(arg) { return arg === undefined; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {a is NonNullable} + */ function isObject(arg) { return arg !== null && typeof arg === 'object'; } +/** + * @deprecated since v4.0.0 + * @param {any} e + * @returns {arg is Error} + */ function isError(e) { return ObjectPrototypeToString(e) === '[object Error]' || e instanceof Error; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is Function} + */ function isFunction(arg) { return typeof arg === 'function'; } +/** + * @deprecated since v4.0.0 + * @param {any} arg + * @returns {arg is (boolean | null | number | string | symbol | undefined)} + */ function isPrimitive(arg) { return arg === null || (typeof arg !== 'object' && typeof arg !== 'function'); } +/** + * @param {number} n + * @returns {string} + */ function pad(n) { return StringPrototypePadStart(n.toString(), 2, '0'); } @@ -126,7 +184,9 @@ function pad(n) { const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -// 26 Feb 16:19:34 +/** + * @returns {string} 26 Feb 16:19:34 + */ function timestamp() { const d = new Date(); const t = ArrayPrototypeJoin([ @@ -138,7 +198,11 @@ function timestamp() { } let console; -// Log is just a thin wrapper to console.log that prepends a timestamp +/** + * Log is just a thin wrapper to console.log that prepends a timestamp + * @deprecated since v6.0.0 + * @type {(...args: any[]) => void} + */ function log(...args) { if (!console) { console = require('internal/console/global'); @@ -155,9 +219,9 @@ function log(...args) { * functions as prototype setup using normal JavaScript does not work as * expected during bootstrapping (see mirror.js in r114903). * - * @param {function} ctor Constructor function which needs to inherit the + * @param {Function} ctor Constructor function which needs to inherit the * prototype. - * @param {function} superCtor Constructor function to inherit prototype from. + * @param {Function} superCtor Constructor function to inherit prototype from. * @throws {TypeError} Will error if either constructor is null, or if * the super constructor lacks a prototype. */ @@ -181,6 +245,14 @@ function inherits(ctor, superCtor) { ObjectSetPrototypeOf(ctor.prototype, superCtor.prototype); } +/** + * @deprecated since v6.0.0 + * @template T + * @template S + * @param {T} target + * @param {S} source + * @returns {S extends null ? T : (T & S)} + */ function _extend(target, source) { // Don't do anything if source isn't an object if (source === null || typeof source !== 'object') return target; @@ -204,6 +276,14 @@ const callbackifyOnRejected = hideStackFrames((reason, cb) => { return cb(reason); }); +/** + * @template {(...args: any[]) => Promise} T + * @param {T} original + * @returns {T extends (...args: infer TArgs) => Promise ? + * ((...params: [...TArgs, ((err: Error, ret: TReturn) => any)]) => void) : + * never + * } + */ function callbackify(original) { if (typeof original !== 'function') { throw new ERR_INVALID_ARG_TYPE('original', 'Function', original); @@ -238,6 +318,10 @@ function callbackify(original) { return callbackified; } +/** + * @param {number} err + * @returns {string} + */ function getSystemErrorName(err) { validateNumber(err, 'err'); if (err >= 0 || !NumberIsSafeInteger(err)) { From e3538bbcd2985200cc0390fcc9f0a0fa105fd252 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Tobias=20Nie=C3=9Fen?= Date: Thu, 22 Apr 2021 16:32:52 +0200 Subject: [PATCH 022/110] src: fix abort in pbkdf2 Fixes: https://github.com/nodejs/node/issues/38341 PR-URL: https://github.com/nodejs/node/pull/38354 Reviewed-By: James M Snell Reviewed-By: Filip Skokan Reviewed-By: Anna Henningsen Reviewed-By: Colin Ihrig --- src/crypto/crypto_pbkdf2.cc | 12 +++--------- test/parallel/test-crypto-pbkdf2.js | 12 ++++++++++++ 2 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/crypto/crypto_pbkdf2.cc b/src/crypto/crypto_pbkdf2.cc index cc9a0d072ad13c..495722927ab5be 100644 --- a/src/crypto/crypto_pbkdf2.cc +++ b/src/crypto/crypto_pbkdf2.cc @@ -92,26 +92,20 @@ Maybe PBKDF2Traits::AdditionalConfig( params->iterations = args[offset + 2].As()->Value(); if (params->iterations < 0) { - char msg[1024]; - snprintf(msg, sizeof(msg), "iterations must be <= %d", INT_MAX); - THROW_ERR_OUT_OF_RANGE(env, msg); + THROW_ERR_OUT_OF_RANGE(env, "iterations must be <= %d", INT_MAX); return Nothing(); } params->length = args[offset + 3].As()->Value(); if (params->length < 0) { - char msg[1024]; - snprintf(msg, sizeof(msg), "length must be <= %d", INT_MAX); - THROW_ERR_OUT_OF_RANGE(env, msg); + THROW_ERR_OUT_OF_RANGE(env, "length must be <= %d", INT_MAX); return Nothing(); } Utf8Value name(args.GetIsolate(), args[offset + 4]); params->digest = EVP_get_digestbyname(*name); if (params->digest == nullptr) { - char errmsg[1024]; - snprintf(errmsg, sizeof(errmsg), "Invalid digest: %s", *name); - THROW_ERR_CRYPTO_INVALID_DIGEST(env, errmsg); + THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *name); return Nothing(); } diff --git a/test/parallel/test-crypto-pbkdf2.js b/test/parallel/test-crypto-pbkdf2.js index 260bdd394ce05e..c9ab6a9c48438e 100644 --- a/test/parallel/test-crypto-pbkdf2.js +++ b/test/parallel/test-crypto-pbkdf2.js @@ -231,3 +231,15 @@ if (!common.hasOpenSSL3) { runPBKDF2(new Uint8Array(10), 'salt', 8, 8, hash); }); } + +{ + // This should not crash. + assert.throws( + () => crypto.pbkdf2Sync('1', '2', 1, 1, '%'), + { + code: 'ERR_CRYPTO_INVALID_DIGEST', + name: 'TypeError', + message: 'Invalid digest: %' + } + ); +} From 769a210d550fd8ea6ad3b9a582a1331b724c2612 Mon Sep 17 00:00:00 2001 From: Filip Skokan Date: Thu, 22 Apr 2021 17:08:18 +0200 Subject: [PATCH 023/110] src: refactor to use THROW_* argument based snprintf MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/38357 Reviewed-By: Tobias Nießen Reviewed-By: Anna Henningsen Reviewed-By: James M Snell Reviewed-By: Colin Ihrig --- src/crypto/crypto_cipher.cc | 19 ++++++++----------- src/crypto/crypto_dsa.cc | 4 +--- src/crypto/crypto_hash.cc | 4 +--- src/crypto/crypto_keys.cc | 4 +--- src/crypto/crypto_rsa.cc | 15 ++++++--------- src/crypto/crypto_scrypt.cc | 5 +---- 6 files changed, 18 insertions(+), 33 deletions(-) diff --git a/src/crypto/crypto_cipher.cc b/src/crypto/crypto_cipher.cc index b15795b691ea0b..5ce466582823ae 100644 --- a/src/crypto/crypto_cipher.cc +++ b/src/crypto/crypto_cipher.cc @@ -511,10 +511,10 @@ bool CipherBase::InitAuthenticated( if (mode == EVP_CIPH_GCM_MODE) { if (auth_tag_len != kNoAuthTagLength) { if (!IsValidGCMTagLength(auth_tag_len)) { - char msg[50]; - snprintf(msg, sizeof(msg), - "Invalid authentication tag length: %u", auth_tag_len); - THROW_ERR_CRYPTO_INVALID_AUTH_TAG(env(), msg); + THROW_ERR_CRYPTO_INVALID_AUTH_TAG( + env(), + "Invalid authentication tag length: %u", + auth_tag_len); return false; } @@ -523,9 +523,8 @@ bool CipherBase::InitAuthenticated( } } else { if (auth_tag_len == kNoAuthTagLength) { - char msg[128]; - snprintf(msg, sizeof(msg), "authTagLength required for %s", cipher_type); - THROW_ERR_CRYPTO_INVALID_AUTH_TAG(env(), msg); + THROW_ERR_CRYPTO_INVALID_AUTH_TAG( + env(), "authTagLength required for %s", cipher_type); return false; } @@ -633,10 +632,8 @@ void CipherBase::SetAuthTag(const FunctionCallbackInfo& args) { } if (!is_valid) { - char msg[50]; - snprintf(msg, sizeof(msg), - "Invalid authentication tag length: %u", tag_len); - return THROW_ERR_CRYPTO_INVALID_AUTH_TAG(env, msg); + return THROW_ERR_CRYPTO_INVALID_AUTH_TAG( + env, "Invalid authentication tag length: %u", tag_len); } cipher->auth_tag_len_ = tag_len; diff --git a/src/crypto/crypto_dsa.cc b/src/crypto/crypto_dsa.cc index 6ee8cf7e18c02e..271db427fa8539 100644 --- a/src/crypto/crypto_dsa.cc +++ b/src/crypto/crypto_dsa.cc @@ -84,9 +84,7 @@ Maybe DsaKeyGenTraits::AdditionalConfig( params->params.modulus_bits = args[*offset].As()->Value(); params->params.divisor_bits = args[*offset + 1].As()->Value(); if (params->params.divisor_bits < -1) { - char msg[1024]; - snprintf(msg, sizeof(msg), "invalid value for divisor_bits"); - THROW_ERR_OUT_OF_RANGE(env, msg); + THROW_ERR_OUT_OF_RANGE(env, "invalid value for divisor_bits"); return Nothing(); } diff --git a/src/crypto/crypto_hash.cc b/src/crypto/crypto_hash.cc index 664ffb847215af..ba2c52268a23ff 100644 --- a/src/crypto/crypto_hash.cc +++ b/src/crypto/crypto_hash.cc @@ -233,9 +233,7 @@ Maybe HashTraits::AdditionalConfig( Utf8Value digest(env->isolate(), args[offset]); params->digest = EVP_get_digestbyname(*digest); if (UNLIKELY(params->digest == nullptr)) { - char msg[1024]; - snprintf(msg, sizeof(msg), "Invalid digest: %s", *digest); - THROW_ERR_CRYPTO_INVALID_DIGEST(env); + THROW_ERR_CRYPTO_INVALID_DIGEST(env, "Invalid digest: %s", *digest); return Nothing(); } diff --git a/src/crypto/crypto_keys.cc b/src/crypto/crypto_keys.cc index be12022bdb7f1d..21cc988cee6a18 100644 --- a/src/crypto/crypto_keys.cc +++ b/src/crypto/crypto_keys.cc @@ -515,9 +515,7 @@ std::shared_ptr ImportJWKAsymmetricKey( return ImportJWKEcKey(env, jwk, args, offset); } - char msg[1024]; - snprintf(msg, sizeof(msg), "%s is not a supported JWK key type", kty); - THROW_ERR_CRYPTO_INVALID_JWK(env, msg); + THROW_ERR_CRYPTO_INVALID_JWK(env, "%s is not a supported JWK key type", kty); return std::shared_ptr(); } diff --git a/src/crypto/crypto_rsa.cc b/src/crypto/crypto_rsa.cc index a77ded918ebdda..5fa91cce1a6ad2 100644 --- a/src/crypto/crypto_rsa.cc +++ b/src/crypto/crypto_rsa.cc @@ -138,9 +138,7 @@ Maybe RsaKeyGenTraits::AdditionalConfig( Utf8Value digest(env->isolate(), args[*offset]); params->params.md = EVP_get_digestbyname(*digest); if (params->params.md == nullptr) { - char msg[1024]; - snprintf(msg, sizeof(msg), "md specifies an invalid digest"); - THROW_ERR_CRYPTO_INVALID_DIGEST(env, msg); + THROW_ERR_CRYPTO_INVALID_DIGEST(env, "md specifies an invalid digest"); return Nothing(); } } @@ -150,9 +148,8 @@ Maybe RsaKeyGenTraits::AdditionalConfig( Utf8Value digest(env->isolate(), args[*offset + 1]); params->params.mgf1_md = EVP_get_digestbyname(*digest); if (params->params.mgf1_md == nullptr) { - char msg[1024]; - snprintf(msg, sizeof(msg), "mgf1_md specifies an invalid digest"); - THROW_ERR_CRYPTO_INVALID_DIGEST(env, msg); + THROW_ERR_CRYPTO_INVALID_DIGEST(env, + "mgf1_md specifies an invalid digest"); return Nothing(); } } @@ -161,9 +158,9 @@ Maybe RsaKeyGenTraits::AdditionalConfig( CHECK(args[*offset + 2]->IsInt32()); params->params.saltlen = args[*offset + 2].As()->Value(); if (params->params.saltlen < 0) { - char msg[1024]; - snprintf(msg, sizeof(msg), "salt length is out of range"); - THROW_ERR_OUT_OF_RANGE(env, msg); + THROW_ERR_OUT_OF_RANGE( + env, + "salt length is out of range"); return Nothing(); } } diff --git a/src/crypto/crypto_scrypt.cc b/src/crypto/crypto_scrypt.cc index 39d6b3fd0d8d6a..077c26554b2f1f 100644 --- a/src/crypto/crypto_scrypt.cc +++ b/src/crypto/crypto_scrypt.cc @@ -111,9 +111,7 @@ Maybe ScryptTraits::AdditionalConfig( params->length = args[offset + 6].As()->Value(); if (params->length < 0) { - char msg[1024]; - snprintf(msg, sizeof(msg), "length must be <= %d", INT_MAX); - THROW_ERR_OUT_OF_RANGE(env, msg); + THROW_ERR_OUT_OF_RANGE(env, "length must be <= %d", INT_MAX); return Nothing(); } @@ -151,4 +149,3 @@ bool ScryptTraits::DeriveBits( } // namespace crypto } // namespace node - From b3ca1b358e4f81a41bb20b9e29ac27d17a24e2b5 Mon Sep 17 00:00:00 2001 From: Giora Guttsait Date: Tue, 20 Apr 2021 23:13:59 +0300 Subject: [PATCH 024/110] timers: remove redundant unref calls PR-URL: https://github.com/nodejs/node/pull/38320 Reviewed-By: James M Snell Reviewed-By: Benjamin Gruenbaum Reviewed-By: Rich Trott --- lib/timers/promises.js | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/timers/promises.js b/lib/timers/promises.js index ec13e873d8443c..1f245580f86ab5 100644 --- a/lib/timers/promises.js +++ b/lib/timers/promises.js @@ -61,8 +61,7 @@ function setTimeout(after, value, options = {}) { } let oncancel; const ret = new Promise((resolve, reject) => { - const timeout = new Timeout(resolve, after, args, false, true); - if (!ref) timeout.unref(); + const timeout = new Timeout(resolve, after, args, false, ref); insert(timeout, timeout._idleTimeout); if (signal) { oncancel = FunctionPrototypeBind(cancelListenerHandler, @@ -141,8 +140,7 @@ async function* setInterval(after, value, options = {}) { callback(); callback = undefined; } - }, after, undefined, true, true); - if (!ref) interval.unref(); + }, after, undefined, true, ref); insert(interval, interval._idleTimeout); if (signal) { onCancel = () => { From 76885cd5780b0d359a27b7a837b4db9f13fce8f0 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 22 Apr 2021 17:05:58 +0200 Subject: [PATCH 025/110] doc: fix `package.json` `"imports"` field history Refs: https://github.com/nodejs/node/pull/34117 PR-URL: https://github.com/nodejs/node/pull/38356 Reviewed-By: Guy Bedford Reviewed-By: Luigi Pinca Reviewed-By: Colin Ihrig Reviewed-By: Shingo Inoue --- doc/api/packages.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/api/packages.md b/doc/api/packages.md index eae5d3b6206f55..e6a7bc9e584ca3 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -1118,7 +1118,9 @@ All paths defined in the `"exports"` must be relative file URLs starting with ### `"imports"` * Type: {Object} From a9314cda7da8dc159f87832e0613c3531893d5e6 Mon Sep 17 00:00:00 2001 From: Antoine du Hamel Date: Thu, 22 Apr 2021 16:52:49 +0200 Subject: [PATCH 026/110] doc: fix version history for `"exports"` patterns Refs: https://github.com/nodejs/node/pull/34718 PR-URL: https://github.com/nodejs/node/pull/38355 Reviewed-By: Guy Bedford Reviewed-By: Colin Ihrig Reviewed-By: Shingo Inoue --- doc/api/packages.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/api/packages.md b/doc/api/packages.md index e6a7bc9e584ca3..f91184208af43e 100644 --- a/doc/api/packages.md +++ b/doc/api/packages.md @@ -336,7 +336,7 @@ analogous to the exports field. For packages with a small number of exports or imports, we recommend @@ -1076,6 +1076,7 @@ added: v12.7.0 changes: - version: - v14.13.0 + - v12.20.0 pr-url: https://github.com/nodejs/node/pull/34718 description: Add support for `"exports"` patterns. - version: From 62b03bc4f63c878015d2ae985ce1becda380158e Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Apr 2021 03:49:53 -0700 Subject: [PATCH 027/110] debugger: move node-inspect to internal library MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit node-inspect developers have agreed to move node-inspect into core rather than vendor it as a dependency. Refs: https://github.com/nodejs/node/discussions/36481 PR-URL: https://github.com/nodejs/node/pull/38161 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- lib/internal/inspector/_inspect.js | 369 +++++++ lib/internal/inspector/inspect_client.js | 355 +++++++ lib/internal/inspector/inspect_repl.js | 1112 ++++++++++++++++++++++ lib/internal/main/inspect.js | 2 +- node.gyp | 6 +- 5 files changed, 1840 insertions(+), 4 deletions(-) create mode 100644 lib/internal/inspector/_inspect.js create mode 100644 lib/internal/inspector/inspect_client.js create mode 100644 lib/internal/inspector/inspect_repl.js diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js new file mode 100644 index 00000000000000..df4e53979db8fd --- /dev/null +++ b/lib/internal/inspector/_inspect.js @@ -0,0 +1,369 @@ +/* + * Copyright Node.js contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +// TODO(trott): enable ESLint +/* eslint-disable */ + +'use strict'; +const { spawn } = require('child_process'); +const { EventEmitter } = require('events'); +const net = require('net'); +const util = require('util'); + +const runAsStandalone = typeof __dirname !== 'undefined'; + +const { 0: InspectClient, 1: createRepl } = + runAsStandalone ? + // This copy of node-inspect is on-disk, relative paths make sense. + [ + require('./inspect_client'), + require('./inspect_repl'), + ] : + // This copy of node-inspect is built into the node executable. + [ + require('internal/inspector/inspect_client'), + require('internal/inspector/inspect_repl'), + ]; + +const debuglog = util.debuglog('inspect'); + +class StartupError extends Error { + constructor(message) { + super(message); + this.name = 'StartupError'; + } +} + +function portIsFree(host, port, timeout = 9999) { + if (port === 0) return Promise.resolve(); // Binding to a random port. + + const retryDelay = 150; + let didTimeOut = false; + + return new Promise((resolve, reject) => { + setTimeout(() => { + didTimeOut = true; + reject(new StartupError( + `Timeout (${timeout}) waiting for ${host}:${port} to be free`)); + }, timeout); + + function pingPort() { + if (didTimeOut) return; + + const socket = net.connect(port, host); + let didRetry = false; + function retry() { + if (!didRetry && !didTimeOut) { + didRetry = true; + setTimeout(pingPort, retryDelay); + } + } + + socket.on('error', (error) => { + if (error.code === 'ECONNREFUSED') { + resolve(); + } else { + retry(); + } + }); + socket.on('connect', () => { + socket.destroy(); + retry(); + }); + } + pingPort(); + }); +} + +function runScript(script, scriptArgs, inspectHost, inspectPort, childPrint) { + return portIsFree(inspectHost, inspectPort) + .then(() => { + return new Promise((resolve) => { + const needDebugBrk = process.version.match(/^v(6|7)\./); + const args = (needDebugBrk ? + ['--inspect', `--debug-brk=${inspectPort}`] : + [`--inspect-brk=${inspectPort}`]) + .concat([script], scriptArgs); + const child = spawn(process.execPath, args); + child.stdout.setEncoding('utf8'); + child.stderr.setEncoding('utf8'); + child.stdout.on('data', childPrint); + child.stderr.on('data', childPrint); + + let output = ''; + function waitForListenHint(text) { + output += text; + if (/Debugger listening on ws:\/\/\[?(.+?)\]?:(\d+)\//.test(output)) { + const host = RegExp.$1; + const port = Number.parseInt(RegExp.$2); + child.stderr.removeListener('data', waitForListenHint); + resolve([child, port, host]); + } + } + + child.stderr.on('data', waitForListenHint); + }); + }); +} + +function createAgentProxy(domain, client) { + const agent = new EventEmitter(); + agent.then = (...args) => { + // TODO: potentially fetch the protocol and pretty-print it here. + const descriptor = { + [util.inspect.custom](depth, { stylize }) { + return stylize(`[Agent ${domain}]`, 'special'); + }, + }; + return Promise.resolve(descriptor).then(...args); + }; + + return new Proxy(agent, { + get(target, name) { + if (name in target) return target[name]; + return function callVirtualMethod(params) { + return client.callMethod(`${domain}.${name}`, params); + }; + }, + }); +} + +class NodeInspector { + constructor(options, stdin, stdout) { + this.options = options; + this.stdin = stdin; + this.stdout = stdout; + + this.paused = true; + this.child = null; + + if (options.script) { + this._runScript = runScript.bind(null, + options.script, + options.scriptArgs, + options.host, + options.port, + this.childPrint.bind(this)); + } else { + this._runScript = + () => Promise.resolve([null, options.port, options.host]); + } + + this.client = new InspectClient(); + + this.domainNames = ['Debugger', 'HeapProfiler', 'Profiler', 'Runtime']; + this.domainNames.forEach((domain) => { + this[domain] = createAgentProxy(domain, this.client); + }); + this.handleDebugEvent = (fullName, params) => { + const { 0: domain, 1: name } = fullName.split('.'); + if (domain in this) { + this[domain].emit(name, params); + } + }; + this.client.on('debugEvent', this.handleDebugEvent); + const startRepl = createRepl(this); + + // Handle all possible exits + process.on('exit', () => this.killChild()); + process.once('SIGTERM', process.exit.bind(process, 0)); + process.once('SIGHUP', process.exit.bind(process, 0)); + + this.run() + .then(() => startRepl()) + .then((repl) => { + this.repl = repl; + this.repl.on('exit', () => { + process.exit(0); + }); + this.paused = false; + }) + .then(null, (error) => process.nextTick(() => { throw error; })); + } + + suspendReplWhile(fn) { + if (this.repl) { + this.repl.pause(); + } + this.stdin.pause(); + this.paused = true; + return new Promise((resolve) => { + resolve(fn()); + }).then(() => { + this.paused = false; + if (this.repl) { + this.repl.resume(); + this.repl.displayPrompt(); + } + this.stdin.resume(); + }).then(null, (error) => process.nextTick(() => { throw error; })); + } + + killChild() { + this.client.reset(); + if (this.child) { + this.child.kill(); + this.child = null; + } + } + + run() { + this.killChild(); + + return this._runScript().then(({ 0: child, 1: port, 2: host }) => { + this.child = child; + + let connectionAttempts = 0; + const attemptConnect = () => { + ++connectionAttempts; + debuglog('connection attempt #%d', connectionAttempts); + this.stdout.write('.'); + return this.client.connect(port, host) + .then(() => { + debuglog('connection established'); + this.stdout.write(' ok'); + }, (error) => { + debuglog('connect failed', error); + // If it's failed to connect 10 times then print failed message + if (connectionAttempts >= 10) { + this.stdout.write(' failed to connect, please retry\n'); + process.exit(1); + } + + return new Promise((resolve) => setTimeout(resolve, 500)) + .then(attemptConnect); + }); + }; + + this.print(`connecting to ${host}:${port} ..`, true); + return attemptConnect(); + }); + } + + clearLine() { + if (this.stdout.isTTY) { + this.stdout.cursorTo(0); + this.stdout.clearLine(1); + } else { + this.stdout.write('\b'); + } + } + + print(text, oneline = false) { + this.clearLine(); + this.stdout.write(oneline ? text : `${text}\n`); + } + + childPrint(text) { + this.print( + text.toString() + .split(/\r\n|\r|\n/g) + .filter((chunk) => !!chunk) + .map((chunk) => `< ${chunk}`) + .join('\n') + ); + if (!this.paused) { + this.repl.displayPrompt(true); + } + if (/Waiting for the debugger to disconnect\.\.\.\n$/.test(text)) { + this.killChild(); + } + } +} + +function parseArgv([target, ...args]) { + let host = '127.0.0.1'; + let port = 9229; + let isRemote = false; + let script = target; + let scriptArgs = args; + + const hostMatch = target.match(/^([^:]+):(\d+)$/); + const portMatch = target.match(/^--port=(\d+)$/); + + if (hostMatch) { + // Connecting to remote debugger + host = hostMatch[1]; + port = parseInt(hostMatch[2], 10); + isRemote = true; + script = null; + } else if (portMatch) { + // Start on custom port + port = parseInt(portMatch[1], 10); + script = args[0]; + scriptArgs = args.slice(1); + } else if (args.length === 1 && /^\d+$/.test(args[0]) && target === '-p') { + // Start debugger against a given pid + const pid = parseInt(args[0], 10); + try { + process._debugProcess(pid); + } catch (e) { + if (e.code === 'ESRCH') { + console.error(`Target process: ${pid} doesn't exist.`); + process.exit(1); + } + throw e; + } + script = null; + isRemote = true; + } + + return { + host, port, isRemote, script, scriptArgs, + }; +} + +function startInspect(argv = process.argv.slice(2), + stdin = process.stdin, + stdout = process.stdout) { + if (argv.length < 1) { + const invokedAs = runAsStandalone ? + 'node-inspect' : + `${process.argv0} ${process.argv[1]}`; + + console.error(`Usage: ${invokedAs} script.js`); + console.error(` ${invokedAs} :`); + console.error(` ${invokedAs} -p `); + process.exit(1); + } + + const options = parseArgv(argv); + const inspector = new NodeInspector(options, stdin, stdout); + + stdin.resume(); + + function handleUnexpectedError(e) { + if (!(e instanceof StartupError)) { + console.error('There was an internal error in Node.js. ' + + 'Please report this bug.'); + console.error(e.message); + console.error(e.stack); + } else { + console.error(e.message); + } + if (inspector.child) inspector.child.kill(); + process.exit(1); + } + + process.on('uncaughtException', handleUnexpectedError); +} +exports.start = startInspect; diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/inspector/inspect_client.js new file mode 100644 index 00000000000000..6010f4ac09389d --- /dev/null +++ b/lib/internal/inspector/inspect_client.js @@ -0,0 +1,355 @@ +/* + * Copyright Node.js contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +// TODO(trott): enable ESLint +/* eslint-disable */ + +'use strict'; +const Buffer = require('buffer').Buffer; +const { EventEmitter } = require('events'); +const http = require('http'); +const URL = require('url'); +const util = require('util'); + +const debuglog = util.debuglog('inspect'); + +const kOpCodeText = 0x1; +const kOpCodeClose = 0x8; + +const kFinalBit = 0x80; +const kReserved1Bit = 0x40; +const kReserved2Bit = 0x20; +const kReserved3Bit = 0x10; +const kOpCodeMask = 0xF; +const kMaskBit = 0x80; +const kPayloadLengthMask = 0x7F; + +const kMaxSingleBytePayloadLength = 125; +const kMaxTwoBytePayloadLength = 0xFFFF; +const kTwoBytePayloadLengthField = 126; +const kEightBytePayloadLengthField = 127; +const kMaskingKeyWidthInBytes = 4; + +function isEmpty(obj) { + return Object.keys(obj).length === 0; +} + +function unpackError({ code, message, data }) { + const err = new Error(`${message} - ${data}`); + err.code = code; + Error.captureStackTrace(err, unpackError); + return err; +} + +function encodeFrameHybi17(payload) { + var i; + + const dataLength = payload.length; + + let singleByteLength; + let additionalLength; + if (dataLength > kMaxTwoBytePayloadLength) { + singleByteLength = kEightBytePayloadLengthField; + additionalLength = Buffer.alloc(8); + let remaining = dataLength; + for (i = 0; i < 8; ++i) { + additionalLength[7 - i] = remaining & 0xFF; + remaining >>= 8; + } + } else if (dataLength > kMaxSingleBytePayloadLength) { + singleByteLength = kTwoBytePayloadLengthField; + additionalLength = Buffer.alloc(2); + additionalLength[0] = (dataLength & 0xFF00) >> 8; + additionalLength[1] = dataLength & 0xFF; + } else { + additionalLength = Buffer.alloc(0); + singleByteLength = dataLength; + } + + const header = Buffer.from([ + kFinalBit | kOpCodeText, + kMaskBit | singleByteLength, + ]); + + const mask = Buffer.alloc(4); + const masked = Buffer.alloc(dataLength); + for (i = 0; i < dataLength; ++i) { + masked[i] = payload[i] ^ mask[i % kMaskingKeyWidthInBytes]; + } + + return Buffer.concat([header, additionalLength, mask, masked]); +} + +function decodeFrameHybi17(data) { + const dataAvailable = data.length; + const notComplete = { closed: false, payload: null, rest: data }; + let payloadOffset = 2; + if ((dataAvailable - payloadOffset) < 0) return notComplete; + + const firstByte = data[0]; + const secondByte = data[1]; + + const final = (firstByte & kFinalBit) !== 0; + const reserved1 = (firstByte & kReserved1Bit) !== 0; + const reserved2 = (firstByte & kReserved2Bit) !== 0; + const reserved3 = (firstByte & kReserved3Bit) !== 0; + const opCode = firstByte & kOpCodeMask; + const masked = (secondByte & kMaskBit) !== 0; + const compressed = reserved1; + if (compressed) { + throw new Error('Compressed frames not supported'); + } + if (!final || reserved2 || reserved3) { + throw new Error('Only compression extension is supported'); + } + + if (masked) { + throw new Error('Masked server frame - not supported'); + } + + let closed = false; + switch (opCode) { + case kOpCodeClose: + closed = true; + break; + case kOpCodeText: + break; + default: + throw new Error(`Unsupported op code ${opCode}`); + } + + let payloadLength = secondByte & kPayloadLengthMask; + switch (payloadLength) { + case kTwoBytePayloadLengthField: + payloadOffset += 2; + payloadLength = (data[2] << 8) + data[3]; + break; + + case kEightBytePayloadLengthField: + payloadOffset += 8; + payloadLength = 0; + for (var i = 0; i < 8; ++i) { + payloadLength <<= 8; + payloadLength |= data[2 + i]; + } + break; + + default: + // Nothing. We already have the right size. + } + if ((dataAvailable - payloadOffset - payloadLength) < 0) return notComplete; + + const payloadEnd = payloadOffset + payloadLength; + return { + payload: data.slice(payloadOffset, payloadEnd), + rest: data.slice(payloadEnd), + closed, + }; +} + +class Client extends EventEmitter { + constructor() { + super(); + this.handleChunk = this._handleChunk.bind(this); + + this._port = undefined; + this._host = undefined; + + this.reset(); + } + + _handleChunk(chunk) { + this._unprocessed = Buffer.concat([this._unprocessed, chunk]); + + while (this._unprocessed.length > 2) { + const { + closed, + payload: payloadBuffer, + rest + } = decodeFrameHybi17(this._unprocessed); + this._unprocessed = rest; + + if (closed) { + this.reset(); + return; + } + if (payloadBuffer === null || payloadBuffer.length === 0) break; + + const payloadStr = payloadBuffer.toString(); + debuglog('< %s', payloadStr); + const lastChar = payloadStr[payloadStr.length - 1]; + if (payloadStr[0] !== '{' || lastChar !== '}') { + throw new Error(`Payload does not look like JSON: ${payloadStr}`); + } + let payload; + try { + payload = JSON.parse(payloadStr); + } catch (parseError) { + parseError.string = payloadStr; + throw parseError; + } + + const { id, method, params, result, error } = payload; + if (id) { + const handler = this._pending[id]; + if (handler) { + delete this._pending[id]; + handler(error, result); + } + } else if (method) { + this.emit('debugEvent', method, params); + this.emit(method, params); + } else { + throw new Error(`Unsupported response: ${payloadStr}`); + } + } + } + + reset() { + if (this._http) { + this._http.destroy(); + } + this._http = null; + this._lastId = 0; + this._socket = null; + this._pending = {}; + this._unprocessed = Buffer.alloc(0); + } + + callMethod(method, params) { + return new Promise((resolve, reject) => { + if (!this._socket) { + reject(new Error('Use `run` to start the app again.')); + return; + } + const data = { id: ++this._lastId, method, params }; + this._pending[data.id] = (error, result) => { + if (error) reject(unpackError(error)); + else resolve(isEmpty(result) ? undefined : result); + }; + const json = JSON.stringify(data); + debuglog('> %s', json); + this._socket.write(encodeFrameHybi17(Buffer.from(json))); + }); + } + + _fetchJSON(urlPath) { + return new Promise((resolve, reject) => { + const httpReq = http.get({ + host: this._host, + port: this._port, + path: urlPath, + }); + + const chunks = []; + + function onResponse(httpRes) { + function parseChunks() { + const resBody = Buffer.concat(chunks).toString(); + if (httpRes.statusCode !== 200) { + reject(new Error(`Unexpected ${httpRes.statusCode}: ${resBody}`)); + return; + } + try { + resolve(JSON.parse(resBody)); + } catch (parseError) { + reject(new Error(`Response didn't contain JSON: ${resBody}`)); + + } + } + + httpRes.on('error', reject); + httpRes.on('data', (chunk) => chunks.push(chunk)); + httpRes.on('end', parseChunks); + } + + httpReq.on('error', reject); + httpReq.on('response', onResponse); + }); + } + + connect(port, host) { + this._port = port; + this._host = host; + return this._discoverWebsocketPath() + .then((urlPath) => this._connectWebsocket(urlPath)); + } + + _discoverWebsocketPath() { + return this._fetchJSON('/json') + .then(({ 0: { webSocketDebuggerUrl } }) => + URL.parse(webSocketDebuggerUrl).path); + } + + _connectWebsocket(urlPath) { + this.reset(); + + const key1 = require('crypto').randomBytes(16).toString('base64'); + debuglog('request websocket', key1); + + const httpReq = this._http = http.request({ + host: this._host, + port: this._port, + path: urlPath, + headers: { + 'Connection': 'Upgrade', + 'Upgrade': 'websocket', + 'Sec-WebSocket-Key': key1, + 'Sec-WebSocket-Version': '13', + }, + }); + httpReq.on('error', (e) => { + this.emit('error', e); + }); + httpReq.on('response', (httpRes) => { + if (httpRes.statusCode >= 400) { + process.stderr.write(`Unexpected HTTP code: ${httpRes.statusCode}\n`); + httpRes.pipe(process.stderr); + } else { + httpRes.pipe(process.stderr); + } + }); + + const handshakeListener = (res, socket) => { + // TODO: we *could* validate res.headers[sec-websocket-accept] + debuglog('websocket upgrade'); + + this._socket = socket; + socket.on('data', this.handleChunk); + socket.on('close', () => { + this.emit('close'); + }); + + this.emit('ready'); + }; + + return new Promise((resolve, reject) => { + this.once('error', reject); + this.once('ready', resolve); + + httpReq.on('upgrade', handshakeListener); + httpReq.end(); + }); + } +} + +module.exports = Client; diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js new file mode 100644 index 00000000000000..7d5b019e28506d --- /dev/null +++ b/lib/internal/inspector/inspect_repl.js @@ -0,0 +1,1112 @@ +/* + * Copyright Node.js contributors. All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to + * deal in the Software without restriction, including without limitation the + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or + * sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +// TODO(trott): enable ESLint +/* eslint-disable */ + +'use strict'; +const FS = require('fs'); +const Path = require('path'); +const Repl = require('repl'); +const util = require('util'); +const vm = require('vm'); +const fileURLToPath = require('url').fileURLToPath; + +const debuglog = util.debuglog('inspect'); + +const SHORTCUTS = { + cont: 'c', + next: 'n', + step: 's', + out: 'o', + backtrace: 'bt', + setBreakpoint: 'sb', + clearBreakpoint: 'cb', + run: 'r', +}; + +const HELP = ` +run, restart, r Run the application or reconnect +kill Kill a running application or disconnect + +cont, c Resume execution +next, n Continue to next line in current file +step, s Step into, potentially entering a function +out, o Step out, leaving the current function +backtrace, bt Print the current backtrace +list Print the source around the current line where execution + is currently paused + +setBreakpoint, sb Set a breakpoint +clearBreakpoint, cb Clear a breakpoint +breakpoints List all known breakpoints +breakOnException Pause execution whenever an exception is thrown +breakOnUncaught Pause execution whenever an exception isn't caught +breakOnNone Don't pause on exceptions (this is the default) + +watch(expr) Start watching the given expression +unwatch(expr) Stop watching an expression +watchers Print all watched expressions and their current values + +exec(expr) Evaluate the expression and print the value +repl Enter a debug repl that works like exec + +scripts List application scripts that are currently loaded +scripts(true) List all scripts (including node-internals) + +profile Start CPU profiling session. +profileEnd Stop current CPU profiling session. +profiles Array of completed CPU profiling sessions. +profiles[n].save(filepath = 'node.cpuprofile') + Save CPU profiling session to disk as JSON. + +takeHeapSnapshot(filepath = 'node.heapsnapshot') + Take a heap snapshot and save to disk as JSON. +`.trim(); + +const FUNCTION_NAME_PATTERN = /^(?:function\*? )?([^(\s]+)\(/; +function extractFunctionName(description) { + const fnNameMatch = description.match(FUNCTION_NAME_PATTERN); + return fnNameMatch ? `: ${fnNameMatch[1]}` : ''; +} + +const PUBLIC_BUILTINS = require('module').builtinModules; +const NATIVES = PUBLIC_BUILTINS ? process.binding('natives') : {}; +function isNativeUrl(url) { + url = url.replace(/\.js$/, ''); + if (PUBLIC_BUILTINS) { + if (url.startsWith('internal/') || PUBLIC_BUILTINS.includes(url)) + return true; + } + + return url in NATIVES || url === 'bootstrap_node'; +} + +function getRelativePath(filenameOrURL) { + const dir = Path.join(Path.resolve(), 'x').slice(0, -1); + + const filename = filenameOrURL.startsWith('file://') ? + fileURLToPath(filenameOrURL) : filenameOrURL; + + // Change path to relative, if possible + if (filename.indexOf(dir) === 0) { + return filename.slice(dir.length); + } + return filename; +} + +function toCallback(promise, callback) { + function forward(...args) { + process.nextTick(() => callback(...args)); + } + promise.then(forward.bind(null, null), forward); +} + +// Adds spaces and prefix to number +// maxN is a maximum number we should have space for +function leftPad(n, prefix, maxN) { + const s = n.toString(); + const nchars = Math.max(2, String(maxN).length) + 1; + const nspaces = nchars - s.length - 1; + + return prefix + ' '.repeat(nspaces) + s; +} + +function markSourceColumn(sourceText, position, useColors) { + if (!sourceText) return ''; + + const head = sourceText.slice(0, position); + let tail = sourceText.slice(position); + + // Colourize char if stdout supports colours + if (useColors) { + tail = tail.replace(/(.+?)([^\w]|$)/, '\u001b[32m$1\u001b[39m$2'); + } + + // Return source line with coloured char at `position` + return [head, tail].join(''); +} + +function extractErrorMessage(stack) { + if (!stack) return ''; + const m = stack.match(/^\w+: ([^\n]+)/); + return m ? m[1] : stack; +} + +function convertResultToError(result) { + const { className, description } = result; + const err = new Error(extractErrorMessage(description)); + err.stack = description; + Object.defineProperty(err, 'name', { value: className }); + return err; +} + +class RemoteObject { + constructor(attributes) { + Object.assign(this, attributes); + if (this.type === 'number') { + this.value = + this.unserializableValue ? +this.unserializableValue : +this.value; + } + } + + [util.inspect.custom](depth, opts) { + function formatProperty(prop) { + switch (prop.type) { + case 'string': + case 'undefined': + return util.inspect(prop.value, opts); + + case 'number': + case 'boolean': + return opts.stylize(prop.value, prop.type); + + case 'object': + case 'symbol': + if (prop.subtype === 'date') { + return util.inspect(new Date(prop.value), opts); + } + if (prop.subtype === 'array') { + return opts.stylize(prop.value, 'special'); + } + return opts.stylize(prop.value, prop.subtype || 'special'); + + default: + return prop.value; + } + } + switch (this.type) { + case 'boolean': + case 'number': + case 'string': + case 'undefined': + return util.inspect(this.value, opts); + + case 'symbol': + return opts.stylize(this.description, 'special'); + + case 'function': { + const fnName = extractFunctionName(this.description); + const formatted = `[${this.className}${fnName}]`; + return opts.stylize(formatted, 'special'); + } + + case 'object': + switch (this.subtype) { + case 'date': + return util.inspect(new Date(this.description), opts); + + case 'null': + return util.inspect(null, opts); + + case 'regexp': + return opts.stylize(this.description, 'regexp'); + + default: + break; + } + if (this.preview) { + const props = this.preview.properties + .map((prop, idx) => { + const value = formatProperty(prop); + if (prop.name === `${idx}`) return value; + return `${prop.name}: ${value}`; + }); + if (this.preview.overflow) { + props.push('...'); + } + const singleLine = props.join(', '); + const propString = + singleLine.length > 60 ? props.join(',\n ') : singleLine; + + return this.subtype === 'array' ? + `[ ${propString} ]` : `{ ${propString} }`; + } + return this.description; + + default: + return this.description; + } + } + + static fromEvalResult({ result, wasThrown }) { + if (wasThrown) return convertResultToError(result); + return new RemoteObject(result); + } +} + +class ScopeSnapshot { + constructor(scope, properties) { + Object.assign(this, scope); + this.properties = new Map(properties.map((prop) => { + const value = new RemoteObject(prop.value); + return [prop.name, value]; + })); + this.completionGroup = properties.map((prop) => prop.name); + } + + [util.inspect.custom](depth, opts) { + const type = `${this.type[0].toUpperCase()}${this.type.slice(1)}`; + const name = this.name ? `<${this.name}>` : ''; + const prefix = `${type}${name} `; + return util.inspect(this.properties, opts) + .replace(/^Map /, prefix); + } +} + +function copyOwnProperties(target, source) { + Object.getOwnPropertyNames(source).forEach((prop) => { + const descriptor = Object.getOwnPropertyDescriptor(source, prop); + Object.defineProperty(target, prop, descriptor); + }); +} + +function aliasProperties(target, mapping) { + Object.keys(mapping).forEach((key) => { + const descriptor = Object.getOwnPropertyDescriptor(target, key); + Object.defineProperty(target, mapping[key], descriptor); + }); +} + +function createRepl(inspector) { + const { Debugger, HeapProfiler, Profiler, Runtime } = inspector; + + let repl; + + // Things we want to keep around + const history = { control: [], debug: [] }; + const watchedExpressions = []; + const knownBreakpoints = []; + let pauseOnExceptionState = 'none'; + let lastCommand; + + // Things we need to reset when the app restarts + let knownScripts; + let currentBacktrace; + let selectedFrame; + let exitDebugRepl; + + function resetOnStart() { + knownScripts = {}; + currentBacktrace = null; + selectedFrame = null; + + if (exitDebugRepl) exitDebugRepl(); + exitDebugRepl = null; + } + resetOnStart(); + + const INSPECT_OPTIONS = { colors: inspector.stdout.isTTY }; + function inspect(value) { + return util.inspect(value, INSPECT_OPTIONS); + } + + function print(value, oneline = false) { + const text = typeof value === 'string' ? value : inspect(value); + return inspector.print(text, oneline); + } + + function getCurrentLocation() { + if (!selectedFrame) { + throw new Error('Requires execution to be paused'); + } + return selectedFrame.location; + } + + function isCurrentScript(script) { + return selectedFrame && getCurrentLocation().scriptId === script.scriptId; + } + + function formatScripts(displayNatives = false) { + function isVisible(script) { + if (displayNatives) return true; + return !script.isNative || isCurrentScript(script); + } + + return Object.keys(knownScripts) + .map((scriptId) => knownScripts[scriptId]) + .filter(isVisible) + .map((script) => { + const isCurrent = isCurrentScript(script); + const { isNative, url } = script; + const name = `${getRelativePath(url)}${isNative ? ' ' : ''}`; + return `${isCurrent ? '*' : ' '} ${script.scriptId}: ${name}`; + }) + .join('\n'); + } + function listScripts(displayNatives = false) { + print(formatScripts(displayNatives)); + } + listScripts[util.inspect.custom] = function listWithoutInternal() { + return formatScripts(); + }; + + const profiles = []; + class Profile { + constructor(data) { + this.data = data; + } + + static createAndRegister({ profile }) { + const p = new Profile(profile); + profiles.push(p); + return p; + } + + [util.inspect.custom](depth, { stylize }) { + const { startTime, endTime } = this.data; + return stylize(`[Profile ${endTime - startTime}μs]`, 'special'); + } + + save(filename = 'node.cpuprofile') { + const absoluteFile = Path.resolve(filename); + const json = JSON.stringify(this.data); + FS.writeFileSync(absoluteFile, json); + print('Saved profile to ' + absoluteFile); + } + } + + class SourceSnippet { + constructor(location, delta, scriptSource) { + Object.assign(this, location); + this.scriptSource = scriptSource; + this.delta = delta; + } + + [util.inspect.custom](depth, options) { + const { scriptId, lineNumber, columnNumber, delta, scriptSource } = this; + const start = Math.max(1, lineNumber - delta + 1); + const end = lineNumber + delta + 1; + + const lines = scriptSource.split('\n'); + return lines.slice(start - 1, end).map((lineText, offset) => { + const i = start + offset; + const isCurrent = i === (lineNumber + 1); + + const markedLine = isCurrent + ? markSourceColumn(lineText, columnNumber, options.colors) + : lineText; + + let isBreakpoint = false; + knownBreakpoints.forEach(({ location }) => { + if (!location) return; + if (scriptId === location.scriptId && + i === (location.lineNumber + 1)) { + isBreakpoint = true; + } + }); + + let prefixChar = ' '; + if (isCurrent) { + prefixChar = '>'; + } else if (isBreakpoint) { + prefixChar = '*'; + } + return `${leftPad(i, prefixChar, end)} ${markedLine}`; + }).join('\n'); + } + } + + function getSourceSnippet(location, delta = 5) { + const { scriptId } = location; + return Debugger.getScriptSource({ scriptId }) + .then(({ scriptSource }) => + new SourceSnippet(location, delta, scriptSource)); + } + + class CallFrame { + constructor(callFrame) { + Object.assign(this, callFrame); + } + + loadScopes() { + return Promise.all( + this.scopeChain + .filter((scope) => scope.type !== 'global') + .map((scope) => { + const { objectId } = scope.object; + return Runtime.getProperties({ + objectId, + generatePreview: true, + }).then(({ result }) => new ScopeSnapshot(scope, result)); + }) + ); + } + + list(delta = 5) { + return getSourceSnippet(this.location, delta); + } + } + + class Backtrace extends Array { + [util.inspect.custom]() { + return this.map((callFrame, idx) => { + const { + location: { scriptId, lineNumber, columnNumber }, + functionName + } = callFrame; + const name = functionName || '(anonymous)'; + + const script = knownScripts[scriptId]; + const relativeUrl = + (script && getRelativePath(script.url)) || ''; + const frameLocation = + `${relativeUrl}:${lineNumber + 1}:${columnNumber}`; + + return `#${idx} ${name} ${frameLocation}`; + }).join('\n'); + } + + static from(callFrames) { + return super.from(Array.from(callFrames).map((callFrame) => { + if (callFrame instanceof CallFrame) { + return callFrame; + } + return new CallFrame(callFrame); + })); + } + } + + function prepareControlCode(input) { + if (input === '\n') return lastCommand; + // exec process.title => exec("process.title"); + const match = input.match(/^\s*exec\s+([^\n]*)/); + if (match) { + lastCommand = `exec(${JSON.stringify(match[1])})`; + } else { + lastCommand = input; + } + return lastCommand; + } + + function evalInCurrentContext(code) { + // Repl asked for scope variables + if (code === '.scope') { + if (!selectedFrame) { + return Promise.reject(new Error('Requires execution to be paused')); + } + return selectedFrame.loadScopes().then((scopes) => { + return scopes.map((scope) => scope.completionGroup); + }); + } + + if (selectedFrame) { + return Debugger.evaluateOnCallFrame({ + callFrameId: selectedFrame.callFrameId, + expression: code, + objectGroup: 'node-inspect', + generatePreview: true, + }).then(RemoteObject.fromEvalResult); + } + return Runtime.evaluate({ + expression: code, + objectGroup: 'node-inspect', + generatePreview: true, + }).then(RemoteObject.fromEvalResult); + } + + function controlEval(input, context, filename, callback) { + debuglog('eval:', input); + function returnToCallback(error, result) { + debuglog('end-eval:', input, error); + callback(error, result); + } + + try { + const code = prepareControlCode(input); + const result = vm.runInContext(code, context, filename); + + if (result && typeof result.then === 'function') { + toCallback(result, returnToCallback); + return; + } + returnToCallback(null, result); + } catch (e) { + returnToCallback(e); + } + } + + function debugEval(input, context, filename, callback) { + debuglog('eval:', input); + function returnToCallback(error, result) { + debuglog('end-eval:', input, error); + callback(error, result); + } + + try { + const result = evalInCurrentContext(input); + + if (result && typeof result.then === 'function') { + toCallback(result, returnToCallback); + return; + } + returnToCallback(null, result); + } catch (e) { + returnToCallback(e); + } + } + + function formatWatchers(verbose = false) { + if (!watchedExpressions.length) { + return Promise.resolve(''); + } + + const inspectValue = (expr) => + evalInCurrentContext(expr) + // .then(formatValue) + .catch((error) => `<${error.message}>`); + const lastIndex = watchedExpressions.length - 1; + + return Promise.all(watchedExpressions.map(inspectValue)) + .then((values) => { + const lines = watchedExpressions + .map((expr, idx) => { + const prefix = `${leftPad(idx, ' ', lastIndex)}: ${expr} =`; + const value = inspect(values[idx], { colors: true }); + if (value.indexOf('\n') === -1) { + return `${prefix} ${value}`; + } + return `${prefix}\n ${value.split('\n').join('\n ')}`; + }); + return lines.join('\n'); + }) + .then((valueList) => { + return verbose ? `Watchers:\n${valueList}\n` : valueList; + }); + } + + function watchers(verbose = false) { + return formatWatchers(verbose).then(print); + } + + // List source code + function list(delta = 5) { + return selectedFrame.list(delta) + .then(null, (error) => { + print('You can\'t list source code right now'); + throw error; + }); + } + + function handleBreakpointResolved({ breakpointId, location }) { + const script = knownScripts[location.scriptId]; + const scriptUrl = script && script.url; + if (scriptUrl) { + Object.assign(location, { scriptUrl }); + } + const isExisting = knownBreakpoints.some((bp) => { + if (bp.breakpointId === breakpointId) { + Object.assign(bp, { location }); + return true; + } + return false; + }); + if (!isExisting) { + knownBreakpoints.push({ breakpointId, location }); + } + } + + function listBreakpoints() { + if (!knownBreakpoints.length) { + print('No breakpoints yet'); + return; + } + + function formatLocation(location) { + if (!location) return ''; + const script = knownScripts[location.scriptId]; + const scriptUrl = script ? script.url : location.scriptUrl; + return `${getRelativePath(scriptUrl)}:${location.lineNumber + 1}`; + } + const breaklist = knownBreakpoints + .map((bp, idx) => `#${idx} ${formatLocation(bp.location)}`) + .join('\n'); + print(breaklist); + } + + function setBreakpoint(script, line, condition, silent) { + function registerBreakpoint({ breakpointId, actualLocation }) { + handleBreakpointResolved({ breakpointId, location: actualLocation }); + if (actualLocation && actualLocation.scriptId) { + if (!silent) return getSourceSnippet(actualLocation, 5); + } else { + print(`Warning: script '${script}' was not loaded yet.`); + } + return undefined; + } + + // setBreakpoint(): set breakpoint at current location + if (script === undefined) { + return Debugger + .setBreakpoint({ location: getCurrentLocation(), condition }) + .then(registerBreakpoint); + } + + // setBreakpoint(line): set breakpoint in current script at specific line + if (line === undefined && typeof script === 'number') { + const location = { + scriptId: getCurrentLocation().scriptId, + lineNumber: script - 1, + }; + return Debugger.setBreakpoint({ location, condition }) + .then(registerBreakpoint); + } + + if (typeof script !== 'string') { + throw new TypeError(`setBreakpoint() expects a string, got ${script}`); + } + + // setBreakpoint('fn()'): Break when a function is called + if (script.endsWith('()')) { + const debugExpr = `debug(${script.slice(0, -2)})`; + const debugCall = selectedFrame + ? Debugger.evaluateOnCallFrame({ + callFrameId: selectedFrame.callFrameId, + expression: debugExpr, + includeCommandLineAPI: true, + }) + : Runtime.evaluate({ + expression: debugExpr, + includeCommandLineAPI: true, + }); + return debugCall.then(({ result, wasThrown }) => { + if (wasThrown) return convertResultToError(result); + return undefined; // This breakpoint can't be removed the same way + }); + } + + // setBreakpoint('scriptname') + let scriptId = null; + let ambiguous = false; + if (knownScripts[script]) { + scriptId = script; + } else { + for (const id of Object.keys(knownScripts)) { + const scriptUrl = knownScripts[id].url; + if (scriptUrl && scriptUrl.indexOf(script) !== -1) { + if (scriptId !== null) { + ambiguous = true; + } + scriptId = id; + } + } + } + + if (ambiguous) { + print('Script name is ambiguous'); + return undefined; + } + if (line <= 0) { + print('Line should be a positive value'); + return undefined; + } + + if (scriptId !== null) { + const location = { scriptId, lineNumber: line - 1 }; + return Debugger.setBreakpoint({ location, condition }) + .then(registerBreakpoint); + } + + const escapedPath = script.replace(/([/\\.?*()^${}|[\]])/g, '\\$1'); + const urlRegex = `^(.*[\\/\\\\])?${escapedPath}$`; + + return Debugger + .setBreakpointByUrl({ urlRegex, lineNumber: line - 1, condition }) + .then((bp) => { + // TODO: handle bp.locations in case the regex matches existing files + if (!bp.location) { // Fake it for now. + Object.assign(bp, { + actualLocation: { + scriptUrl: `.*/${script}$`, + lineNumber: line - 1, + }, + }); + } + return registerBreakpoint(bp); + }); + } + + function clearBreakpoint(url, line) { + const breakpoint = knownBreakpoints.find(({ location }) => { + if (!location) return false; + const script = knownScripts[location.scriptId]; + if (!script) return false; + return ( + script.url.indexOf(url) !== -1 && (location.lineNumber + 1) === line + ); + }); + if (!breakpoint) { + print(`Could not find breakpoint at ${url}:${line}`); + return Promise.resolve(); + } + return Debugger.removeBreakpoint({ breakpointId: breakpoint.breakpointId }) + .then(() => { + const idx = knownBreakpoints.indexOf(breakpoint); + knownBreakpoints.splice(idx, 1); + }); + } + + function restoreBreakpoints() { + const lastBreakpoints = knownBreakpoints.slice(); + knownBreakpoints.length = 0; + const newBreakpoints = lastBreakpoints + .filter(({ location }) => !!location.scriptUrl) + .map(({ location }) => + setBreakpoint(location.scriptUrl, location.lineNumber + 1)); + if (!newBreakpoints.length) return Promise.resolve(); + return Promise.all(newBreakpoints).then((results) => { + print(`${results.length} breakpoints restored.`); + }); + } + + function setPauseOnExceptions(state) { + return Debugger.setPauseOnExceptions({ state }) + .then(() => { + pauseOnExceptionState = state; + }); + } + + Debugger.on('paused', ({ callFrames, reason /* , hitBreakpoints */ }) => { + if (process.env.NODE_INSPECT_RESUME_ON_START === '1' && + reason === 'Break on start') { + debuglog('Paused on start, but NODE_INSPECT_RESUME_ON_START' + + ' environment variable is set to 1, resuming'); + inspector.client.callMethod('Debugger.resume'); + return; + } + + // Save execution context's data + currentBacktrace = Backtrace.from(callFrames); + selectedFrame = currentBacktrace[0]; + const { scriptId, lineNumber } = selectedFrame.location; + + const breakType = reason === 'other' ? 'break' : reason; + const script = knownScripts[scriptId]; + const scriptUrl = script ? getRelativePath(script.url) : '[unknown]'; + + const header = `${breakType} in ${scriptUrl}:${lineNumber + 1}`; + + inspector.suspendReplWhile(() => + Promise.all([formatWatchers(true), selectedFrame.list(2)]) + .then(([watcherList, context]) => { + if (watcherList) { + return `${watcherList}\n${inspect(context)}`; + } + return inspect(context); + }).then((breakContext) => { + print(`${header}\n${breakContext}`); + })); + }); + + function handleResumed() { + currentBacktrace = null; + selectedFrame = null; + } + + Debugger.on('resumed', handleResumed); + + Debugger.on('breakpointResolved', handleBreakpointResolved); + + Debugger.on('scriptParsed', (script) => { + const { scriptId, url } = script; + if (url) { + knownScripts[scriptId] = Object.assign({ + isNative: isNativeUrl(url), + }, script); + } + }); + + Profiler.on('consoleProfileFinished', ({ profile }) => { + Profile.createAndRegister({ profile }); + print([ + 'Captured new CPU profile.', + `Access it with profiles[${profiles.length - 1}]` + ].join('\n')); + }); + + function initializeContext(context) { + inspector.domainNames.forEach((domain) => { + Object.defineProperty(context, domain, { + value: inspector[domain], + enumerable: true, + configurable: true, + writeable: false, + }); + }); + + copyOwnProperties(context, { + get help() { + print(HELP); + }, + + get run() { + return inspector.run(); + }, + + get kill() { + return inspector.killChild(); + }, + + get restart() { + return inspector.run(); + }, + + get cont() { + handleResumed(); + return Debugger.resume(); + }, + + get next() { + handleResumed(); + return Debugger.stepOver(); + }, + + get step() { + handleResumed(); + return Debugger.stepInto(); + }, + + get out() { + handleResumed(); + return Debugger.stepOut(); + }, + + get pause() { + return Debugger.pause(); + }, + + get backtrace() { + return currentBacktrace; + }, + + get breakpoints() { + return listBreakpoints(); + }, + + exec(expr) { + return evalInCurrentContext(expr); + }, + + get profile() { + return Profiler.start(); + }, + + get profileEnd() { + return Profiler.stop() + .then(Profile.createAndRegister); + }, + + get profiles() { + return profiles; + }, + + takeHeapSnapshot(filename = 'node.heapsnapshot') { + return new Promise((resolve, reject) => { + const absoluteFile = Path.resolve(filename); + const writer = FS.createWriteStream(absoluteFile); + let sizeWritten = 0; + function onProgress({ done, total, finished }) { + if (finished) { + print('Heap snaphost prepared.'); + } else { + print(`Heap snapshot: ${done}/${total}`, true); + } + } + function onChunk({ chunk }) { + sizeWritten += chunk.length; + writer.write(chunk); + print(`Writing snapshot: ${sizeWritten}`, true); + } + function onResolve() { + writer.end(() => { + teardown(); + print(`Wrote snapshot: ${absoluteFile}`); + resolve(); + }); + } + function onReject(error) { + teardown(); + reject(error); + } + function teardown() { + HeapProfiler.removeListener( + 'reportHeapSnapshotProgress', onProgress); + HeapProfiler.removeListener('addHeapSnapshotChunk', onChunk); + } + + HeapProfiler.on('reportHeapSnapshotProgress', onProgress); + HeapProfiler.on('addHeapSnapshotChunk', onChunk); + + print('Heap snapshot: 0/0', true); + HeapProfiler.takeHeapSnapshot({ reportProgress: true }) + .then(onResolve, onReject); + }); + }, + + get watchers() { + return watchers(); + }, + + watch(expr) { + watchedExpressions.push(expr); + }, + + unwatch(expr) { + const index = watchedExpressions.indexOf(expr); + + // Unwatch by expression + // or + // Unwatch by watcher number + watchedExpressions.splice(index !== -1 ? index : +expr, 1); + }, + + get repl() { + // Don't display any default messages + const listeners = repl.listeners('SIGINT').slice(0); + repl.removeAllListeners('SIGINT'); + + const oldContext = repl.context; + + exitDebugRepl = () => { + // Restore all listeners + process.nextTick(() => { + listeners.forEach((listener) => { + repl.on('SIGINT', listener); + }); + }); + + // Exit debug repl + repl.eval = controlEval; + + // Swap history + history.debug = repl.history; + repl.history = history.control; + + repl.context = oldContext; + repl.setPrompt('debug> '); + repl.displayPrompt(); + + repl.removeListener('SIGINT', exitDebugRepl); + repl.removeListener('exit', exitDebugRepl); + + exitDebugRepl = null; + }; + + // Exit debug repl on SIGINT + repl.on('SIGINT', exitDebugRepl); + + // Exit debug repl on repl exit + repl.on('exit', exitDebugRepl); + + // Set new + repl.eval = debugEval; + repl.context = {}; + + // Swap history + history.control = repl.history; + repl.history = history.debug; + + repl.setPrompt('> '); + + print('Press Ctrl + C to leave debug repl'); + repl.displayPrompt(); + }, + + get version() { + return Runtime.evaluate({ + expression: 'process.versions.v8', + contextId: 1, + returnByValue: true, + }).then(({ result }) => { + print(result.value); + }); + }, + + scripts: listScripts, + + setBreakpoint, + clearBreakpoint, + setPauseOnExceptions, + get breakOnException() { + return setPauseOnExceptions('all'); + }, + get breakOnUncaught() { + return setPauseOnExceptions('uncaught'); + }, + get breakOnNone() { + return setPauseOnExceptions('none'); + }, + + list, + }); + aliasProperties(context, SHORTCUTS); + } + + function initAfterStart() { + const setupTasks = [ + Runtime.enable(), + Profiler.enable(), + Profiler.setSamplingInterval({ interval: 100 }), + Debugger.enable(), + Debugger.setPauseOnExceptions({ state: 'none' }), + Debugger.setAsyncCallStackDepth({ maxDepth: 0 }), + Debugger.setBlackboxPatterns({ patterns: [] }), + Debugger.setPauseOnExceptions({ state: pauseOnExceptionState }), + restoreBreakpoints(), + Runtime.runIfWaitingForDebugger(), + ]; + return Promise.all(setupTasks); + } + + return function startRepl() { + inspector.client.on('close', () => { + resetOnStart(); + }); + inspector.client.on('ready', () => { + initAfterStart(); + }); + + const replOptions = { + prompt: 'debug> ', + input: inspector.stdin, + output: inspector.stdout, + eval: controlEval, + useGlobal: false, + ignoreUndefined: true, + }; + + repl = Repl.start(replOptions); + initializeContext(repl.context); + repl.on('reset', initializeContext); + + repl.defineCommand('interrupt', () => { + // We want this for testing purposes where sending CTRL-C can be tricky. + repl.emit('SIGINT'); + }); + + // Init once for the initial connection + initAfterStart(); + + return repl; + }; +} +module.exports = createRepl; diff --git a/lib/internal/main/inspect.js b/lib/internal/main/inspect.js index 4873683048cc79..d9dab0dc92b118 100644 --- a/lib/internal/main/inspect.js +++ b/lib/internal/main/inspect.js @@ -13,5 +13,5 @@ markBootstrapComplete(); // Start the debugger agent. process.nextTick(() => { - require('internal/deps/node-inspect/lib/_inspect').start(); + require('internal/inspector/_inspect').start(); }); diff --git a/node.gyp b/node.gyp index acae34fa393339..54ede7fe785ad1 100644 --- a/node.gyp +++ b/node.gyp @@ -166,6 +166,9 @@ 'lib/internal/heap_utils.js', 'lib/internal/histogram.js', 'lib/internal/idna.js', + 'lib/internal/inspector/_inspect.js', + 'lib/internal/inspector/inspect_client.js', + 'lib/internal/inspector/inspect_repl.js', 'lib/internal/inspector_async_hook.js', 'lib/internal/js_stream_socket.js', 'lib/internal/legacy/processbinding.js', @@ -277,9 +280,6 @@ 'deps/v8/tools/tickprocessor.mjs', 'deps/v8/tools/sourcemap.mjs', 'deps/v8/tools/tickprocessor-driver.mjs', - 'deps/node-inspect/lib/_inspect.js', - 'deps/node-inspect/lib/internal/inspect_client.js', - 'deps/node-inspect/lib/internal/inspect_repl.js', 'deps/acorn/acorn/dist/acorn.js', 'deps/acorn/acorn-walk/dist/walk.js', 'deps/acorn-plugins/acorn-class-fields/index.js', From 02e875c645db92ecf2a70ba5b9ae31be93b46045 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Apr 2021 03:51:24 -0700 Subject: [PATCH 028/110] tools: remove node-inspect from license MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- LICENSE | 23 ----------------------- tools/license-builder.sh | 3 --- 2 files changed, 26 deletions(-) diff --git a/LICENSE b/LICENSE index c6c4f14e2dc193..41f9bc05611a82 100644 --- a/LICENSE +++ b/LICENSE @@ -1333,29 +1333,6 @@ The externally maintained libraries used by Node.js are: WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ -- node-inspect, located at deps/node-inspect, is licensed as follows: - """ - Copyright Node.js contributors. All rights reserved. - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to - deal in the Software without restriction, including without limitation the - rights to use, copy, modify, merge, publish, distribute, sublicense, and/or - sell copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING - FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS - IN THE SOFTWARE. - """ - - large_pages, located at src/large_pages, is licensed as follows: """ Copyright (C) 2018 Intel Corporation diff --git a/tools/license-builder.sh b/tools/license-builder.sh index 05a15471c7e77f..80aaac11b1cade 100755 --- a/tools/license-builder.sh +++ b/tools/license-builder.sh @@ -89,9 +89,6 @@ addlicense "gtest" "test/cctest/gtest" "$(cat "${rootdir}"/test/cctest/gtest/LIC # nghttp2 addlicense "nghttp2" "deps/nghttp2" "$(cat "${rootdir}"/deps/nghttp2/COPYING)" -# node-inspect -addlicense "node-inspect" "deps/node-inspect" "$(cat "${rootdir}"/deps/node-inspect/LICENSE)" - # large_pages addlicense "large_pages" "src/large_pages" "$(sed -e '/SPDX-License-Identifier/,$d' -e 's/^\/\///' "${rootdir}"/src/large_pages/node_large_page.h)" From d65615e119994ff071e90c19173d257fddfa962b Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Apr 2021 04:05:12 -0700 Subject: [PATCH 029/110] debugger: remove unused code MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Remove code that was for when `node-inspect` was called as a standalone process. PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- lib/internal/inspector/_inspect.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index df4e53979db8fd..8bc1f13e5726f0 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -29,16 +29,7 @@ const { EventEmitter } = require('events'); const net = require('net'); const util = require('util'); -const runAsStandalone = typeof __dirname !== 'undefined'; - const { 0: InspectClient, 1: createRepl } = - runAsStandalone ? - // This copy of node-inspect is on-disk, relative paths make sense. - [ - require('./inspect_client'), - require('./inspect_repl'), - ] : - // This copy of node-inspect is built into the node executable. [ require('internal/inspector/inspect_client'), require('internal/inspector/inspect_repl'), @@ -336,9 +327,7 @@ function startInspect(argv = process.argv.slice(2), stdin = process.stdin, stdout = process.stdout) { if (argv.length < 1) { - const invokedAs = runAsStandalone ? - 'node-inspect' : - `${process.argv0} ${process.argv[1]}`; + const invokedAs = `${process.argv0} ${process.argv[1]}`; console.error(`Usage: ${invokedAs} script.js`); console.error(` ${invokedAs} :`); From 07361e6b77d9cdf1999ea0c86621e5acff42da97 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 20 Apr 2021 07:17:28 -0700 Subject: [PATCH 030/110] debugger: fix inspect restart on Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Fixes: https://github.com/nodejs/node/issues/37224 PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- lib/internal/inspector/inspect_client.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/internal/inspector/inspect_client.js b/lib/internal/inspector/inspect_client.js index 6010f4ac09389d..831a7fda1cdff1 100644 --- a/lib/internal/inspector/inspect_client.js +++ b/lib/internal/inspector/inspect_client.js @@ -228,6 +228,9 @@ class Client extends EventEmitter { if (this._http) { this._http.destroy(); } + if (this._socket) { + this._socket.destroy(); + } this._http = null; this._lastId = 0; this._socket = null; From def85daaceb96e511d7568ad8acdc34fc39b593e Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Tue, 20 Apr 2021 22:46:42 -0700 Subject: [PATCH 031/110] debugger: accommodate line chunking in Windows MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- lib/internal/inspector/_inspect.js | 43 ++++++++++++++++---------- lib/internal/inspector/inspect_repl.js | 10 +++--- 2 files changed, 31 insertions(+), 22 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index 8bc1f13e5726f0..b58b4b695e8505 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -97,8 +97,8 @@ function runScript(script, scriptArgs, inspectHost, inspectPort, childPrint) { const child = spawn(process.execPath, args); child.stdout.setEncoding('utf8'); child.stderr.setEncoding('utf8'); - child.stdout.on('data', childPrint); - child.stderr.on('data', childPrint); + child.stdout.on('data', (chunk) => childPrint(chunk, 'stdout')); + child.stderr.on('data', (chunk) => childPrint(chunk, 'stderr')); let output = ''; function waitForListenHint(text) { @@ -231,7 +231,7 @@ class NodeInspector { return this.client.connect(port, host) .then(() => { debuglog('connection established'); - this.stdout.write(' ok'); + this.stdout.write(' ok\n'); }, (error) => { debuglog('connect failed', error); // If it's failed to connect 10 times then print failed message @@ -245,7 +245,7 @@ class NodeInspector { }); }; - this.print(`connecting to ${host}:${port} ..`, true); + this.print(`connecting to ${host}:${port} ..`, false); return attemptConnect(); }); } @@ -259,23 +259,32 @@ class NodeInspector { } } - print(text, oneline = false) { + print(text, appendNewline = false) { this.clearLine(); - this.stdout.write(oneline ? text : `${text}\n`); + this.stdout.write(appendNewline ? `${text}\n` : text); } - childPrint(text) { - this.print( - text.toString() - .split(/\r\n|\r|\n/g) - .filter((chunk) => !!chunk) - .map((chunk) => `< ${chunk}`) - .join('\n') - ); - if (!this.paused) { - this.repl.displayPrompt(true); + #stdioBuffers = {stdout: '', stderr: ''}; + childPrint(text, which) { + const lines = (this.#stdioBuffers[which] + text) + .split(/\r\n|\r|\n/g); + + this.#stdioBuffers[which] = ''; + + if (lines[lines.length - 1] !== '') { + this.#stdioBuffers[which] = lines.pop(); + } + + const textToPrint = lines.map((chunk) => `< ${chunk}`).join('\n'); + + if (lines.length) { + this.print(textToPrint, true); + if (!this.paused) { + this.repl.displayPrompt(true); + } } - if (/Waiting for the debugger to disconnect\.\.\.\n$/.test(text)) { + + if (textToPrint.endsWith('Waiting for the debugger to disconnect...\n')) { this.killChild(); } } diff --git a/lib/internal/inspector/inspect_repl.js b/lib/internal/inspector/inspect_repl.js index 7d5b019e28506d..7fd9772eef733b 100644 --- a/lib/internal/inspector/inspect_repl.js +++ b/lib/internal/inspector/inspect_repl.js @@ -320,9 +320,9 @@ function createRepl(inspector) { return util.inspect(value, INSPECT_OPTIONS); } - function print(value, oneline = false) { + function print(value, addNewline = true) { const text = typeof value === 'string' ? value : inspect(value); - return inspector.print(text, oneline); + return inspector.print(text, addNewline); } function getCurrentLocation() { @@ -928,13 +928,13 @@ function createRepl(inspector) { if (finished) { print('Heap snaphost prepared.'); } else { - print(`Heap snapshot: ${done}/${total}`, true); + print(`Heap snapshot: ${done}/${total}`, false); } } function onChunk({ chunk }) { sizeWritten += chunk.length; writer.write(chunk); - print(`Writing snapshot: ${sizeWritten}`, true); + print(`Writing snapshot: ${sizeWritten}`, false); } function onResolve() { writer.end(() => { @@ -956,7 +956,7 @@ function createRepl(inspector) { HeapProfiler.on('reportHeapSnapshotProgress', onProgress); HeapProfiler.on('addHeapSnapshotChunk', onChunk); - print('Heap snapshot: 0/0', true); + print('Heap snapshot: 0/0', false); HeapProfiler.takeHeapSnapshot({ reportProgress: true }) .then(onResolve, onReject); }); From 6fff9fff9728d94825b5d839357f4dcafb530743 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Wed, 21 Apr 2021 16:22:36 -0700 Subject: [PATCH 032/110] debugger: allow longer time to connect MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Make five attempts with a timeout of 1 second each rather than 10 attempts with a timeout of 500ms each. This is to allow for slower-connecting devices like Raspberry Pi. PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- lib/internal/inspector/_inspect.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/internal/inspector/_inspect.js b/lib/internal/inspector/_inspect.js index b58b4b695e8505..b326a772fd39c9 100644 --- a/lib/internal/inspector/_inspect.js +++ b/lib/internal/inspector/_inspect.js @@ -234,13 +234,13 @@ class NodeInspector { this.stdout.write(' ok\n'); }, (error) => { debuglog('connect failed', error); - // If it's failed to connect 10 times then print failed message - if (connectionAttempts >= 10) { + // If it's failed to connect 5 times then print failed message + if (connectionAttempts >= 5) { this.stdout.write(' failed to connect, please retry\n'); process.exit(1); } - return new Promise((resolve) => setTimeout(resolve, 500)) + return new Promise((resolve) => setTimeout(resolve, 1000)) .then(attemptConnect); }); }; From 6c3e5043b00ffaeee718810567bb49660512fab3 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 22 Apr 2021 10:40:12 -0700 Subject: [PATCH 033/110] test: fix test-inspector-cli-address MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The test was assuming that the entire string being sought would arrive in a single data chunk, but it can be split across multiple chunks. PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- deps/node-inspect/test/cli/address.test.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/deps/node-inspect/test/cli/address.test.js b/deps/node-inspect/test/cli/address.test.js index 1dbe4f37b42175..b55a2d078ea4a4 100644 --- a/deps/node-inspect/test/cli/address.test.js +++ b/deps/node-inspect/test/cli/address.test.js @@ -16,7 +16,9 @@ function launchTarget(...args) { }; childProc.on('exit', onExit); childProc.stderr.setEncoding('utf8'); - childProc.stderr.on('data', (data) => { + let data = ''; + childProc.stderr.on('data', (chunk) => { + data += chunk; const ret = kDebuggerMsgReg.exec(data); childProc.removeListener('exit', onExit); if (ret) { From a4084d66c67e6a17df7ea01b54bcbe87e0f5f2d2 Mon Sep 17 00:00:00 2001 From: Rich Trott Date: Thu, 8 Apr 2021 23:55:45 -0700 Subject: [PATCH 034/110] test,debugger: migrate node-inspect tests to core MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Migrate the node-inspect tests to core (where node-inspect code now lives) and remove node-inspect from deps directory. PR-URL: https://github.com/nodejs/node/pull/38161 Refs: https://github.com/nodejs/node/discussions/36481 Reviewed-By: Matteo Collina Reviewed-By: Jan Krems Reviewed-By: Colin Ihrig Reviewed-By: Stephen Belanger Reviewed-By: Gerhard Stöbich Reviewed-By: Michaël Zasso --- Makefile | 4 - deps/node-inspect/.editorconfig | 11 - deps/node-inspect/.eslintrc | 147 --- deps/node-inspect/.github/workflows/ci.yml | 31 - deps/node-inspect/.gitignore | 4 - deps/node-inspect/.npmrc | 2 - deps/node-inspect/.travis.yml | 13 - deps/node-inspect/CHANGELOG.md | 296 ----- deps/node-inspect/CONTRIBUTING.md | 181 --- deps/node-inspect/GOVERNANCE.md | 4 - deps/node-inspect/LICENSE | 19 - deps/node-inspect/README.md | 29 - deps/node-inspect/appveyor.yml | 13 - deps/node-inspect/cli.js | 2 - deps/node-inspect/lib/_inspect.js | 371 ------ deps/node-inspect/lib/cli.js | 24 - .../lib/internal/inspect_client.js | 352 ------ .../node-inspect/lib/internal/inspect_repl.js | 1108 ----------------- deps/node-inspect/package.json | 45 - deps/node-inspect/test/cli/backtrace.test.js | 30 - deps/node-inspect/test/cli/break.test.js | 195 --- deps/node-inspect/test/cli/exec.test.js | 77 -- .../test/cli/heap-profiler.test.js | 34 - deps/node-inspect/test/cli/help.test.js | 22 - .../test/cli/invalid-args.test.js | 54 - deps/node-inspect/test/cli/launch.test.js | 196 --- deps/node-inspect/test/cli/pid.test.js | 52 - .../test/cli/preserve-breaks.test.js | 64 - .../eslint-rules/align-function-arguments.js | 76 -- .../align-multiline-assignment.js | 68 - .../assert-fail-single-argument.js | 30 - .../tools/eslint-rules/buffer-constructor.js | 25 - .../tools/eslint-rules/new-with-error.js | 31 - .../eslint-rules/no-let-in-for-declaration.js | 46 - .../eslint-rules/prefer-assert-methods.js | 39 - .../tools/eslint-rules/require-buffer.js | 19 - .../tools/eslint-rules/required-modules.js | 99 -- lib/internal/inspector/inspect_repl.js | 2 +- test/README.md | 1 + test/common/README.md | 29 + .../common/inspector-cli.js | 75 +- .../fixtures/inspector-cli}/alive.js | 0 .../fixtures/inspector-cli}/backtrace.js | 0 .../fixtures/inspector-cli}/break.js | 0 .../fixtures/inspector-cli}/cjs/index.js | 0 .../fixtures/inspector-cli}/cjs/other.js | 0 .../fixtures/inspector-cli}/empty.js | 0 .../fixtures/inspector-cli}/exceptions.js | 0 .../fixtures/inspector-cli}/three-lines.js | 0 .../fixtures/inspector-cli}/use-strict.js | 0 test/inspector-cli/inspector-cli.status | 7 + .../test-inspector-cli-address.js | 28 +- .../test-inspector-cli-auto-resume.js | 36 + .../test-inspector-cli-backtrace.js | 36 + .../inspector-cli/test-inspector-cli-break.js | 131 ++ .../test-inspector-cli-clear-breakpoints.js | 53 + .../test-inspector-cli-custom-port.js | 30 + .../test-inspector-cli-exceptions.js | 44 +- .../test-inspector-cli-exec-scope.js | 38 + test/inspector-cli/test-inspector-cli-exec.js | 67 + .../test-inspector-cli-heap-profiler.js | 37 + test/inspector-cli/test-inspector-cli-help.js | 27 + .../test-inspector-cli-invalid-args.js | 59 + .../test-inspector-cli-launch.js | 47 + .../test-inspector-cli-low-level.js | 21 +- test/inspector-cli/test-inspector-cli-pid.js | 61 + .../test-inspector-cli-preserve-breaks.js | 72 ++ .../test-inspector-cli-profile.js | 22 +- ...ector-cli-random-port-with-inspect-port.js | 30 + .../test-inspector-cli-random-port.js | 30 + ...st-inspector-cli-run-after-quit-restart.js | 90 ++ .../test-inspector-cli-sb-before-load.js | 44 + .../test-inspector-cli-scripts.js | 32 +- .../test-inspector-cli-use-strict.js | 18 +- .../test-inspector-cli-watchers.js | 30 +- test/inspector-cli/testcfg.py | 6 + 76 files changed, 1083 insertions(+), 3933 deletions(-) delete mode 100644 deps/node-inspect/.editorconfig delete mode 100644 deps/node-inspect/.eslintrc delete mode 100644 deps/node-inspect/.github/workflows/ci.yml delete mode 100644 deps/node-inspect/.gitignore delete mode 100644 deps/node-inspect/.npmrc delete mode 100644 deps/node-inspect/.travis.yml delete mode 100644 deps/node-inspect/CHANGELOG.md delete mode 100644 deps/node-inspect/CONTRIBUTING.md delete mode 100644 deps/node-inspect/GOVERNANCE.md delete mode 100644 deps/node-inspect/LICENSE delete mode 100644 deps/node-inspect/README.md delete mode 100644 deps/node-inspect/appveyor.yml delete mode 100755 deps/node-inspect/cli.js delete mode 100644 deps/node-inspect/lib/_inspect.js delete mode 100644 deps/node-inspect/lib/cli.js delete mode 100644 deps/node-inspect/lib/internal/inspect_client.js delete mode 100644 deps/node-inspect/lib/internal/inspect_repl.js delete mode 100644 deps/node-inspect/package.json delete mode 100644 deps/node-inspect/test/cli/backtrace.test.js delete mode 100644 deps/node-inspect/test/cli/break.test.js delete mode 100644 deps/node-inspect/test/cli/exec.test.js delete mode 100644 deps/node-inspect/test/cli/heap-profiler.test.js delete mode 100644 deps/node-inspect/test/cli/help.test.js delete mode 100644 deps/node-inspect/test/cli/invalid-args.test.js delete mode 100644 deps/node-inspect/test/cli/launch.test.js delete mode 100644 deps/node-inspect/test/cli/pid.test.js delete mode 100644 deps/node-inspect/test/cli/preserve-breaks.test.js delete mode 100644 deps/node-inspect/tools/eslint-rules/align-function-arguments.js delete mode 100644 deps/node-inspect/tools/eslint-rules/align-multiline-assignment.js delete mode 100644 deps/node-inspect/tools/eslint-rules/assert-fail-single-argument.js delete mode 100644 deps/node-inspect/tools/eslint-rules/buffer-constructor.js delete mode 100644 deps/node-inspect/tools/eslint-rules/new-with-error.js delete mode 100644 deps/node-inspect/tools/eslint-rules/no-let-in-for-declaration.js delete mode 100644 deps/node-inspect/tools/eslint-rules/prefer-assert-methods.js delete mode 100644 deps/node-inspect/tools/eslint-rules/require-buffer.js delete mode 100644 deps/node-inspect/tools/eslint-rules/required-modules.js rename deps/node-inspect/test/cli/start-cli.js => test/common/inspector-cli.js (67%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/alive.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/backtrace.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/break.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/cjs/index.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/cjs/other.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/empty.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/exceptions.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/three-lines.js (100%) rename {deps/node-inspect/examples => test/fixtures/inspector-cli}/use-strict.js (100%) create mode 100644 test/inspector-cli/inspector-cli.status rename deps/node-inspect/test/cli/address.test.js => test/inspector-cli/test-inspector-cli-address.js (74%) create mode 100644 test/inspector-cli/test-inspector-cli-auto-resume.js create mode 100644 test/inspector-cli/test-inspector-cli-backtrace.js create mode 100644 test/inspector-cli/test-inspector-cli-break.js create mode 100644 test/inspector-cli/test-inspector-cli-clear-breakpoints.js create mode 100644 test/inspector-cli/test-inspector-cli-custom-port.js rename deps/node-inspect/test/cli/exceptions.test.js => test/inspector-cli/test-inspector-cli-exceptions.js (55%) create mode 100644 test/inspector-cli/test-inspector-cli-exec-scope.js create mode 100644 test/inspector-cli/test-inspector-cli-exec.js create mode 100644 test/inspector-cli/test-inspector-cli-heap-profiler.js create mode 100644 test/inspector-cli/test-inspector-cli-help.js create mode 100644 test/inspector-cli/test-inspector-cli-invalid-args.js create mode 100644 test/inspector-cli/test-inspector-cli-launch.js rename deps/node-inspect/test/cli/low-level.test.js => test/inspector-cli/test-inspector-cli-low-level.js (57%) create mode 100644 test/inspector-cli/test-inspector-cli-pid.js create mode 100644 test/inspector-cli/test-inspector-cli-preserve-breaks.js rename deps/node-inspect/test/cli/profile.test.js => test/inspector-cli/test-inspector-cli-profile.js (52%) create mode 100644 test/inspector-cli/test-inspector-cli-random-port-with-inspect-port.js create mode 100644 test/inspector-cli/test-inspector-cli-random-port.js create mode 100644 test/inspector-cli/test-inspector-cli-run-after-quit-restart.js create mode 100644 test/inspector-cli/test-inspector-cli-sb-before-load.js rename deps/node-inspect/test/cli/scripts.test.js => test/inspector-cli/test-inspector-cli-scripts.js (51%) rename deps/node-inspect/test/cli/use-strict.test.js => test/inspector-cli/test-inspector-cli-use-strict.js (54%) rename deps/node-inspect/test/cli/watchers.test.js => test/inspector-cli/test-inspector-cli-watchers.js (56%) create mode 100644 test/inspector-cli/testcfg.py diff --git a/Makefile b/Makefile index 26746d94f4ab8c..50d6795bc34903 100644 --- a/Makefile +++ b/Makefile @@ -565,10 +565,6 @@ test-pummel: all test-internet: all $(PYTHON) tools/test.py $(PARALLEL_ARGS) internet -test-node-inspect: $(NODE_EXE) - USE_EMBEDDED_NODE_INSPECT=1 $(NODE) tools/test-npm-package \ - --install deps/node-inspect test - test-benchmark: | bench-addons-build $(PYTHON) tools/test.py $(PARALLEL_ARGS) benchmark diff --git a/deps/node-inspect/.editorconfig b/deps/node-inspect/.editorconfig deleted file mode 100644 index beffa3084e7a69..00000000000000 --- a/deps/node-inspect/.editorconfig +++ /dev/null @@ -1,11 +0,0 @@ -root = true - -[*] -indent_style = space -indent_size = 2 -charset = utf-8 -trim_trailing_whitespace = true -insert_final_newline = true - -[*.md] -trim_trailing_whitespace = false diff --git a/deps/node-inspect/.eslintrc b/deps/node-inspect/.eslintrc deleted file mode 100644 index b6d45aa499655b..00000000000000 --- a/deps/node-inspect/.eslintrc +++ /dev/null @@ -1,147 +0,0 @@ -root: true - -env: - node: true - es6: true - -parserOptions: - ecmaVersion: 2017 - -rules: - # Possible Errors - # http://eslint.org/docs/rules/#possible-errors - comma-dangle: [2, only-multiline] - no-control-regex: 2 - no-debugger: 2 - no-dupe-args: 2 - no-dupe-keys: 2 - no-duplicate-case: 2 - no-empty-character-class: 2 - no-ex-assign: 2 - no-extra-boolean-cast: 2 - no-extra-parens: [2, functions] - no-extra-semi: 2 - no-func-assign: 2 - no-invalid-regexp: 2 - no-irregular-whitespace: 2 - no-obj-calls: 2 - no-proto: 2 - no-template-curly-in-string: 2 - no-unexpected-multiline: 2 - no-unreachable: 2 - no-unsafe-negation: 2 - use-isnan: 2 - valid-typeof: 2 - - # Best Practices - # http://eslint.org/docs/rules/#best-practices - dot-location: [2, property] - no-fallthrough: 2 - no-global-assign: 2 - no-multi-spaces: 2 - no-octal: 2 - no-redeclare: 2 - no-self-assign: 2 - no-unused-labels: 2 - no-useless-call: 2 - no-useless-escape: 2 - no-void: 2 - no-with: 2 - - # Strict Mode - # http://eslint.org/docs/rules/#strict-mode - strict: [2, global] - - # Variables - # http://eslint.org/docs/rules/#variables - no-delete-var: 2 - no-undef: 2 - no-unused-vars: [2, {args: none}] - - # Node.js and CommonJS - # http://eslint.org/docs/rules/#nodejs-and-commonjs - no-mixed-requires: 2 - no-new-require: 2 - no-path-concat: 2 - no-restricted-modules: [2, sys, _linklist] - no-restricted-properties: [2, { - object: assert, - property: deepEqual, - message: Please use assert.deepStrictEqual(). - }, { - property: __defineGetter__, - message: __defineGetter__ is deprecated. - }, { - property: __defineSetter__, - message: __defineSetter__ is deprecated. - }] - - # Stylistic Issues - # http://eslint.org/docs/rules/#stylistic-issues - brace-style: [2, 1tbs, {allowSingleLine: true}] - comma-spacing: 2 - comma-style: 2 - computed-property-spacing: 2 - eol-last: 2 - func-call-spacing: 2 - func-name-matching: 2 - indent: [2, 2, {SwitchCase: 1, MemberExpression: 1}] - key-spacing: [2, {mode: minimum}] - keyword-spacing: 2 - linebreak-style: [2, unix] - max-len: [2, 80, 2] - new-parens: 2 - no-mixed-spaces-and-tabs: 2 - no-multiple-empty-lines: [2, {max: 2, maxEOF: 0, maxBOF: 0}] - no-tabs: 2 - no-trailing-spaces: 2 - quotes: [2, single, avoid-escape] - semi: 2 - semi-spacing: 2 - space-before-blocks: [2, always] - space-before-function-paren: [2, never] - space-in-parens: [2, never] - space-infix-ops: 2 - space-unary-ops: 2 - - # ECMAScript 6 - # http://eslint.org/docs/rules/#ecmascript-6 - arrow-parens: [2, always] - arrow-spacing: [2, {before: true, after: true}] - constructor-super: 2 - no-class-assign: 2 - no-confusing-arrow: 2 - no-const-assign: 2 - no-dupe-class-members: 2 - no-new-symbol: 2 - no-this-before-super: 2 - prefer-const: [2, {ignoreReadBeforeAssign: true}] - rest-spread-spacing: 2 - template-curly-spacing: 2 - - # Custom rules in tools/eslint-rules - align-function-arguments: 2 - align-multiline-assignment: 2 - assert-fail-single-argument: 2 - new-with-error: [2, Error, RangeError, TypeError, SyntaxError, ReferenceError] - -# Global scoped method and vars -globals: - COUNTER_HTTP_CLIENT_REQUEST: false - COUNTER_HTTP_CLIENT_RESPONSE: false - COUNTER_HTTP_SERVER_REQUEST: false - COUNTER_HTTP_SERVER_RESPONSE: false - COUNTER_NET_SERVER_CONNECTION: false - COUNTER_NET_SERVER_CONNECTION_CLOSE: false - DTRACE_HTTP_CLIENT_REQUEST: false - DTRACE_HTTP_CLIENT_RESPONSE: false - DTRACE_HTTP_SERVER_REQUEST: false - DTRACE_HTTP_SERVER_RESPONSE: false - DTRACE_NET_SERVER_CONNECTION: false - DTRACE_NET_STREAM_END: false - LTTNG_HTTP_CLIENT_REQUEST: false - LTTNG_HTTP_CLIENT_RESPONSE: false - LTTNG_HTTP_SERVER_REQUEST: false - LTTNG_HTTP_SERVER_RESPONSE: false - LTTNG_NET_SERVER_CONNECTION: false - LTTNG_NET_STREAM_END: false diff --git a/deps/node-inspect/.github/workflows/ci.yml b/deps/node-inspect/.github/workflows/ci.yml deleted file mode 100644 index 968316a34779a5..00000000000000 --- a/deps/node-inspect/.github/workflows/ci.yml +++ /dev/null @@ -1,31 +0,0 @@ -name: Node CI - -on: [push, pull_request] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - fail-fast: false - matrix: - node-version: - # See https://github.com/nodejs/node-inspect/pull/78 - # - 10.x - - 12.x - - 13.x - - steps: - - uses: actions/checkout@v2 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - name: npm install, build, and test - run: | - npm install - npm run build --if-present - npm test - env: - CI: true diff --git a/deps/node-inspect/.gitignore b/deps/node-inspect/.gitignore deleted file mode 100644 index 72e2c8c18012a8..00000000000000 --- a/deps/node-inspect/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -node_modules/ -npm-debug.log -/tmp -/.vs diff --git a/deps/node-inspect/.npmrc b/deps/node-inspect/.npmrc deleted file mode 100644 index b7c8444fee52a6..00000000000000 --- a/deps/node-inspect/.npmrc +++ /dev/null @@ -1,2 +0,0 @@ -registry=https://registry.npmjs.org -package-lock=false diff --git a/deps/node-inspect/.travis.yml b/deps/node-inspect/.travis.yml deleted file mode 100644 index 07418a91eb7986..00000000000000 --- a/deps/node-inspect/.travis.yml +++ /dev/null @@ -1,13 +0,0 @@ -language: node_js -node_js: - - '6.8' -before_deploy: - - git config --global user.email "jan.krems@gmail.com" - - git config --global user.name "Jan Krems" -deploy: - provider: script - script: ./node_modules/.bin/nlm release - skip_cleanup: true - 'on': - branch: master - node: '6.8' diff --git a/deps/node-inspect/CHANGELOG.md b/deps/node-inspect/CHANGELOG.md deleted file mode 100644 index 73aeb4df93fe8b..00000000000000 --- a/deps/node-inspect/CHANGELOG.md +++ /dev/null @@ -1,296 +0,0 @@ -### 1.11.6 - -* fix: replace the deprecated "repl.cli" with "repl" - **[@oyyd](https://github.com/oyyd)** [#66](https://github.com/nodejs/node-inspect/pull/66) - - [`5c1d771`](https://github.com/nodejs/node-inspect/commit/5c1d7716523b73e26f98f4f594ee34b7daa920a0) **fix:** replace the deprecated "repl.cli" with "repl" - see: [26260](Refs: https://github.com/nodejs/node/pull/26260) -* Address regressions due to changes in node - **[@jkrems](https://github.com/jkrems)** [#67](https://github.com/nodejs/node-inspect/pull/67) - - [`5b3511e`](https://github.com/nodejs/node-inspect/commit/5b3511ef21d0eba8304d8b2fed33f33aae22f308) **fix:** Address regressions due to changes in node - - -### 1.11.5 - -* Fix eslint issues - **[@jkrems](https://github.com/jkrems)** [#63](https://github.com/nodejs/node-inspect/pull/63) - - [`2adadbc`](https://github.com/nodejs/node-inspect/commit/2adadbc1086d2e374c425acbf96260a122705db2) **style:** Fix eslint issues - - [`a6d2f88`](https://github.com/nodejs/node-inspect/commit/a6d2f882c026409696a1b063ff40ceba7e1ddb86) **doc:** Remove redundant newline at the end - - -### 1.11.4 - -* Handle blocked port - **[@jkrems](https://github.com/jkrems)** [#62](https://github.com/nodejs/node-inspect/pull/62) - - [`3388969`](https://github.com/nodejs/node-inspect/commit/3388969d0032a78ff0cdb8146f170b978ec13b7b) **chore:** Disable package-lock - - [`d278b23`](https://github.com/nodejs/node-inspect/commit/d278b233ae5e11a2b62d01ccbaae594f39b32a96) **fix:** Stop asking to report a blocked port - see: [#60](https://github.com/nodejs/node-inspect/issues/60) - - -### 1.11.3 - -* [`93caa0f`](https://github.com/nodejs/node-inspect/commit/93caa0f5267c7ab452b258d3b03329a0bb5ac7f7) **docs:** Add missing oc in protocol -* [`2d87cbe`](https://github.com/nodejs/node-inspect/commit/2d87cbe76aa968dfc1ac69d9571af1be81abd8e0) **fix:** Make --inspect-port=0 work -* [`ebfd02e`](https://github.com/nodejs/node-inspect/commit/ebfd02ece9b642586023f7791da71defeb13d746) **chore:** Bump tap to 10.7 -* [`c07adb1`](https://github.com/nodejs/node-inspect/commit/c07adb17b164c1cf3da8d38659ea9f5d7ff42e9c) **test:** Use useful break location -* [`94f0bf9`](https://github.com/nodejs/node-inspect/commit/94f0bf97d24c376baf3ecced2088d81715a73464) **fix:** Fix `takeHeapSnapshot()` truncation bug - - -### 1.11.2 - -* [`42e0cd1`](https://github.com/nodejs/node-inspect/commit/42e0cd111d89ed09faba1c0ec45089b0b44de011) **fix:** look for generic hint text - - -### 1.11.1 - -* Prefer --inspect-brk over --debug-brk - **[@ofrobots](https://github.com/ofrobots)** [#43](https://github.com/nodejs/node-inspect/pull/43) - - [`2c1ed27`](https://github.com/nodejs/node-inspect/commit/2c1ed27ee44d9aebb3c5ac50039abae8166a54e3) **fix:** use --inspect-brk with Node 8+ - - -### 1.11.0 - -* doc: add profile and heap to help - **[@joshgav](https://github.com/joshgav)** [#39](https://github.com/nodejs/node-inspect/pull/39) - - [`f64c920`](https://github.com/nodejs/node-inspect/commit/f64c9205bd8382289660aa677d3ac192a9c81fd5) **doc:** add profile and heap to help -* Update test suite to pass on latest nightly - **[@jkrems](https://github.com/jkrems)** [#36](https://github.com/nodejs/node-inspect/pull/36) - - [`41148d7`](https://github.com/nodejs/node-inspect/commit/41148d74a2d563eea3b7ad5463622b6b9fd4c46e) **test:** Remove outdated test - - [`2c224c5`](https://github.com/nodejs/node-inspect/commit/2c224c551619e386e80fc3154cc14562cac063b9) **test:** Accept any kind of "break" - - [`22bf349`](https://github.com/nodejs/node-inspect/commit/22bf349bc86d7bf6fd449791c9d1e7eaf66c2681) **test:** Adjust for v8 5.7 - - [`6ce8c16`](https://github.com/nodejs/node-inspect/commit/6ce8c165c45a491bea8cfb3c67d2ae80e7c34dcb) **test:** Revert to old assertions -* Verify custom port support - **[@jkrems](https://github.com/jkrems)** [#41](https://github.com/nodejs/node-inspect/pull/41) - - [`e3a489f`](https://github.com/nodejs/node-inspect/commit/e3a489f23b089d3d57a25d5efe40daf06de63e23) **test:** custom port -* Support for debugging a pid - **[@jkrems](https://github.com/jkrems)** [#37](https://github.com/nodejs/node-inspect/pull/37) - - [`4179506`](https://github.com/nodejs/node-inspect/commit/4179506a4d546bac2c93b2a7ff491b1fa4494fd9) **feat:** Support for debugging a pid - - -### 1.10.6 - -* chore: Fix usage text for embedded mode - **[@addaleax](https://github.com/addaleax)** [#20](https://github.com/nodejs/node-inspect/pull/20) - - [`b0779f5`](https://github.com/nodejs/node-inspect/commit/b0779f597104e9ada5681f64d7e714525b753511) **chore:** Fix usage text for embedded mode -* print 'ok' after connection - **[@ofrobots](https://github.com/ofrobots)** [#25](https://github.com/nodejs/node-inspect/pull/25) - - [`2a47125`](https://github.com/nodejs/node-inspect/commit/2a4712577f6996fbb078dcfcd7320c397685d76a) **fix:** print 'ok' after connection -* Make autocompletion in REPL work - **[@aqrln](https://github.com/aqrln)** [#28](https://github.com/nodejs/node-inspect/pull/28) - - [`ccab737`](https://github.com/nodejs/node-inspect/commit/ccab737399249a8c2230ed6adfec579c7d724364) **fix:** Make autocompletion in REPL work -* Remove console.error() statement - **[@aqrln](https://github.com/aqrln)** [#30](https://github.com/nodejs/node-inspect/pull/30) - - [`032b045`](https://github.com/nodejs/node-inspect/commit/032b045d4d73622c77b7ebcc26781c6ad98200b3) **style:** Remove console.error() statement -* Take --debug-port into account - **[@jkrems](https://github.com/jkrems)** [#26](https://github.com/nodejs/node-inspect/pull/26) - - [`054d4b1`](https://github.com/nodejs/node-inspect/commit/054d4b10e65f12a3a4b10b4c0ab2a4768cc5e893) **fix:** Take --debug-port into account -* Delay run until breakpoints are restored - **[@jkrems](https://github.com/jkrems)** [#34](https://github.com/nodejs/node-inspect/pull/34) - - [`802b88c`](https://github.com/nodejs/node-inspect/commit/802b88c8ad0a57608cb9e0cb4bf46ed683bb6344) **fix:** Delay run until breakpoints are restored - - [`2b93173`](https://github.com/nodejs/node-inspect/commit/2b93173d95e7f8b30d85603613cb2ae3b3ec18db) **fix:** Use single string for paused notice - - [`b4d5ee2`](https://github.com/nodejs/node-inspect/commit/b4d5ee2a3d25613b35a2e8e10a0eb75582cc5654) **fix:** Work around inconsistent handling of strict directive - - [`f6ccfc7`](https://github.com/nodejs/node-inspect/commit/f6ccfc7f4d00ad4fdf3b581b677f8d7f1699c44c) **fix:** Only restart after port is free - - [`8b101bf`](https://github.com/nodejs/node-inspect/commit/8b101bf669ca102df4980bfad3e0436ef1c2f1a4) **test:** Skip exact match on AIX -* [`a4e4b6f`](https://github.com/nodejs/node-inspect/commit/a4e4b6feeba4dedfd2c89ef32f39e813314d3bbd) **chore:** Fix repo info in package.json - - -### 1.10.5 - -* docs: minor edits to governance docs - **[@joshgav](https://github.com/joshgav)** [#17](https://github.com/buggerjs/node-inspect/pull/17) - - [`a70fe04`](https://github.com/buggerjs/node-inspect/commit/a70fe04bdde9b7c74588685066291f9b11183328) **docs:** minor edits to governance docs - - -### 1.10.4 - -* [`1c31bf7`](https://github.com/buggerjs/node-inspect/commit/1c31bf7d1b3ea1b424ae0662526596670cb506c9) **chore:** Support embedded mode - - -### 1.10.3 - -* [`7b20379`](https://github.com/buggerjs/node-inspect/commit/7b20379069af692a9038a31a4465f72db9eb532f) **chore:** Mark .eslintrc as root - - -### 1.10.2 - -* Run tests on windows - **[@jkrems](https://github.com/jkrems)** [#16](https://github.com/buggerjs/node-inspect/pull/16) - - [`5a57f98`](https://github.com/buggerjs/node-inspect/commit/5a57f9865e02eef0763c2a7f26236c34a632ccdd) **chore:** Run tests on windows - - [`0a04b50`](https://github.com/buggerjs/node-inspect/commit/0a04b50cc8b4dc6ce868927c635c479d75ce71f4) **chore:** Bump nlm to get rid of postinstall - - [`4a8b27c`](https://github.com/buggerjs/node-inspect/commit/4a8b27cea814a37895effd2a0c1b85dbfee3a7f4) **test:** Remove unix path assumptions - - -### 1.10.1 - -* [`4ba3c72`](https://github.com/buggerjs/node-inspect/commit/4ba3c72270fae9a71343ddca11aa27980678a67c) **refactor:** Undo weird bundling into one file - - -### 1.10.0 - -* [`3e1a66a`](https://github.com/buggerjs/node-inspect/commit/3e1a66a489bef19beaa5f859e99e027274ff43cb) **feat:** Support CPU & heap profiles - - -### 1.9.3 - -* Move back to single file - **[@jkrems](https://github.com/jkrems)** [#15](https://github.com/buggerjs/node-inspect/pull/15) - - [`9877660`](https://github.com/buggerjs/node-inspect/commit/9877660a73ff0ec0885ad7f939ba62020a46b4b6) **refactor:** Wrap client in IIFE - - [`7795c53`](https://github.com/buggerjs/node-inspect/commit/7795c533f0605eb128db610a5874b27e555251ef) **refactor:** Move more code in createRepl scope - - [`be34a39`](https://github.com/buggerjs/node-inspect/commit/be34a398e823612bdf5ac90bad5222af27035a00) **refactor:** Move back to single file - - [`ab45b62`](https://github.com/buggerjs/node-inspect/commit/ab45b6273dc0d3a49d3cf46a80cb48ab79d1caf8) **refactor:** Remove single-use functions - - [`37a711e`](https://github.com/buggerjs/node-inspect/commit/37a711ed5334c06ed4d85f995e567a9f176a68d5) **style:** Stop using `new Buffer` - - [`d669dc5`](https://github.com/buggerjs/node-inspect/commit/d669dc593f5ad5ca7a48f19f0905ef66ec0e540d) **chore:** Switch to node eslint rules - - [`15e7917`](https://github.com/buggerjs/node-inspect/commit/15e79177918d96dcffd2384715faf0308e97a26c) **style:** Use var in classical for loops - - -### 1.9.2 - -* [`c9dc4be`](https://github.com/buggerjs/node-inspect/commit/c9dc4beb08236e33d64f19417682cf5b3f5aeed6) **doc:** Link directly to GOVERNANCE file - - -### 1.9.1 - -* Handle big ws frames correctly - **[@jkrems](https://github.com/jkrems)** [#14](https://github.com/buggerjs/node-inspect/pull/14) - - [`f80100e`](https://github.com/buggerjs/node-inspect/commit/f80100e932710d232d074b239cbf8fefa564c789) **fix:** Handle big ws frames correctly - see: [#10](https://github.com/buggerjs/node-inspect/issues/10) - - -### 1.9.0 - -* Support for low-level agent access - **[@jkrems](https://github.com/jkrems)** [#13](https://github.com/buggerjs/node-inspect/pull/13) - - [`90ed431`](https://github.com/buggerjs/node-inspect/commit/90ed4310c62d130637c12f8ecdb752075c43ac36) **feat:** Support for low-level agent access - - -### 1.8.4 - -* Use proper path for websocket - **[@jkrems](https://github.com/jkrems)** [#12](https://github.com/buggerjs/node-inspect/pull/12) - - [`3405225`](https://github.com/buggerjs/node-inspect/commit/3405225979dfc2058bcc6d1b90f41c060dbd1f92) **fix:** Use proper path for websocket - see: [#11](https://github.com/buggerjs/node-inspect/issues/11) - - -### 1.8.3 - -* [`6f9883d`](https://github.com/buggerjs/node-inspect/commit/6f9883d4b29419831133988981b83e891b19739a) **fix:** Breakpoints & scripts work when not paused -* [`ecb1362`](https://github.com/buggerjs/node-inspect/commit/ecb1362c842e6ed5bc28c091a32bfd540742db75) **chore:** Pin node to 6.8 - - -### 1.8.2 - -* [`4219a98`](https://github.com/buggerjs/node-inspect/commit/4219a98d6514f1068feabce2945c21a0d5ba6561) **refactor:** Decouple source snippet from repl - - -### 1.8.1 - -* [`95402ee`](https://github.com/buggerjs/node-inspect/commit/95402ee5dff04057f074677d39db2f61ec74c151) **refactor:** Move `list` into CallFrame - - -### 1.8.0 - -* [`d0e6499`](https://github.com/buggerjs/node-inspect/commit/d0e6499084f5d656ef0c5fd470d3ab21f2e9a6b4) **feat:** `exec .scope` - - -### 1.7.0 - -* `breakOn{Exception,Uncaught,None}` - **[@jkrems](https://github.com/jkrems)** [#8](https://github.com/buggerjs/node-inspect/pull/8) - - [`fa8c4c7`](https://github.com/buggerjs/node-inspect/commit/fa8c4c7d7bb6972733c92da4d04fdd62c02b0e3b) **feat:** `breakOn{Exception,Uncaught,None}` - see: [#6](https://github.com/buggerjs/node-inspect/issues/6) - - -### 1.6.0 - -* Add `help` command - **[@jkrems](https://github.com/jkrems)** [#7](https://github.com/buggerjs/node-inspect/pull/7) - - [`09b37a0`](https://github.com/buggerjs/node-inspect/commit/09b37a02e04e16a38ce27f69538d3b098548b47c) **feat:** Add `help` command - see: [#5](https://github.com/buggerjs/node-inspect/issues/5) - - -### 1.5.0 - -* [`7e0fd99`](https://github.com/buggerjs/node-inspect/commit/7e0fd99fcfc65d8b647a2259df78f4cabf1d3d63) **feat:** Add `r` shortcut for `run` - - -### 1.4.1 - -* [`484d098`](https://github.com/buggerjs/node-inspect/commit/484d0983f06d6ff9639ab5197ba0a58313f532df) **chore:** Remove old implementation - - -### 1.4.0 - -* Properly tested implementation - **[@jkrems](https://github.com/jkrems)** [#4](https://github.com/buggerjs/node-inspect/pull/4) - - [`ba060d3`](https://github.com/buggerjs/node-inspect/commit/ba060d3ef65ae84df2a3a9b9f16d563f3c4b29be) **feat:** Error handling w/o args - - [`b39b3bc`](https://github.com/buggerjs/node-inspect/commit/b39b3bc07c13adc48fc8bb720889285c51e62548) **feat:** Launch child - - [`481693f`](https://github.com/buggerjs/node-inspect/commit/481693f676ee099b7787cd2426b980858e973602) **feat:** Connect debug client - - [`3bba0f2`](https://github.com/buggerjs/node-inspect/commit/3bba0f2416b2e3b4e6010de675003fcc328b16e8) **chore:** Disable lint for inactive code - - [`cc7bdfc`](https://github.com/buggerjs/node-inspect/commit/cc7bdfcf7f21ef5cd5c32c7800407238b0d4f100) **feat:** Properly fail with invalid host:port - - [`73f34f9`](https://github.com/buggerjs/node-inspect/commit/73f34f902634e9778597e129f46895aa8b643d72) **refactor:** Remove unused field - - [`6a23e0c`](https://github.com/buggerjs/node-inspect/commit/6a23e0cf3179f43ca6fc5a0fa2b1dd18ebc044b5) **refactor:** Better debug output & support node 6.6 - - [`63b0f9b`](https://github.com/buggerjs/node-inspect/commit/63b0f9b6ef8bd9af0f7cb14a5938a45838731fc9) **test:** Add timeout to waitFor(pattern) - - [`cfa197b`](https://github.com/buggerjs/node-inspect/commit/cfa197bf8325a1a4ca1b296f8d6971d368bfbfbb) **refactor:** Move REPL setup into own file - - [`3f46c2c`](https://github.com/buggerjs/node-inspect/commit/3f46c2c43f836e1135b66871087aa74969f6b330) **feat:** Working repl eval - - [`6911eb1`](https://github.com/buggerjs/node-inspect/commit/6911eb1a00b964bc5683506d433fa4f665f5a82c) **feat:** Enter repeats last command - - [`7d20b7d`](https://github.com/buggerjs/node-inspect/commit/7d20b7deadf1b251ea8cf2cc9167c175624932c4) **chore:** Add missing license header - - [`23c62f8`](https://github.com/buggerjs/node-inspect/commit/23c62f8375ca7c8b71d032047e728dace02f4efa) **feat:** Print break context - - [`5dbc83d`](https://github.com/buggerjs/node-inspect/commit/5dbc83df31171f9c38a974c99340bde26f2e24ec) **feat:** Stepping and breakpoints - - [`8deb8cc`](https://github.com/buggerjs/node-inspect/commit/8deb8cc36b9fca432ab8df63a82e9de7ab5adaf0) **feat:** list for printing source - - [`1ed2ec9`](https://github.com/buggerjs/node-inspect/commit/1ed2ec9937070652be611dbb6b11dfb42cb840f8) **chore:** Disable verbose output on CI - - [`625a435`](https://github.com/buggerjs/node-inspect/commit/625a435925dd8fd980bed2dc9e3fd73dd27df4ef) **fix:** Gracefully handle delayed scriptParsed - - [`8823c60`](https://github.com/buggerjs/node-inspect/commit/8823c60d347600b2313cfdd8cb5e96fe02419a8a) **chore:** Run all the tests - - [`00506f7`](https://github.com/buggerjs/node-inspect/commit/00506f763928cc440505a81030167a11b9a84e00) **feat:** backtrace/bt - - [`e1ee02d`](https://github.com/buggerjs/node-inspect/commit/e1ee02d5cc389916489d387d07d5dd161230427a) **refactor:** Leverage util.inspect.custom - - [`5dcc319`](https://github.com/buggerjs/node-inspect/commit/5dcc31922d40f56c7435319d1538390a442e8e4b) **feat:** scripts and scripts(true) - - [`085cd5a`](https://github.com/buggerjs/node-inspect/commit/085cd5a76a961edfcaa342fff5eb09bf2f9c8983) **refactor:** Consistent import style - - [`1c60f91`](https://github.com/buggerjs/node-inspect/commit/1c60f91f233848c05d865617dc7f5aacb36270b6) **feat:** Set breakpoint before file is loaded - - [`bc82ecc`](https://github.com/buggerjs/node-inspect/commit/bc82eccb2a1a7c0f5332371254f6584e748216aa) **feat:** breakpoints to list breakpoints - - [`7f48c95`](https://github.com/buggerjs/node-inspect/commit/7f48c9510696ec400d51afaca8d23a9c292640f8) **feat:** watchers & exec - - [`0f8cd13`](https://github.com/buggerjs/node-inspect/commit/0f8cd13a092e5dbeb395ff04cbe2ed97cb986423) **feat:** clearBreakpoint - - [`0d31560`](https://github.com/buggerjs/node-inspect/commit/0d315603bdcb9f4da42fab24dc569c325151269e) **feat:** version to print v8 version - - [`df6b89d`](https://github.com/buggerjs/node-inspect/commit/df6b89df580a9afcb3b8883b0e4224cbcebb384f) **feat:** Paused & global exec - - [`9e97d73`](https://github.com/buggerjs/node-inspect/commit/9e97d73073ceffd70974d45887c84fadb9159d5c) **feat:** repl to enter exec mode - - [`9ee9f90`](https://github.com/buggerjs/node-inspect/commit/9ee9f903d6202f54ed2b3b3559da4006b65d39b5) **feat:** run & restart -* [`3a752aa`](https://github.com/buggerjs/node-inspect/commit/3a752aaa773968bfe16c5f543bd739feed598bea) **feat:** kill -* [`a67e470`](https://github.com/buggerjs/node-inspect/commit/a67e47018b20d46aeeaa7abd27eb8e7770fd0b8f) **feat:** Restore breakpoints on restart - - -### 1.3.3 - -* [`eb7a54c`](https://github.com/buggerjs/node-inspect/commit/eb7a54c6fa731ed3276072c72034046fc5ffbac6) **chore:** Switch to tap for tests - - -### 1.3.2 - -* Add notes about governance - **[@jkrems](https://github.com/jkrems)** [#3](https://github.com/buggerjs/node-inspect/pull/3) - - [`e94089d`](https://github.com/buggerjs/node-inspect/commit/e94089d93689cacf5c953e94563463d1e174452d) **chore:** Add notes about governance - - -### 1.3.1 - -* [`8767137`](https://github.com/buggerjs/node-inspect/commit/8767137c53a2f6b1d36970074ea95be9871e50e3) **style:** Remove rogue console.log - - -### 1.3.0 - -* [`3ac6232`](https://github.com/buggerjs/node-inspect/commit/3ac623219ba44b0af40ef66826610a26a46c7966) **feat:** Add `version` command - - -### 1.2.0 - -* [`86b5812`](https://github.com/buggerjs/node-inspect/commit/86b581218ccab44e6bde259a17ad1e71645a6137) **feat:** scripts & listScripts(true) - - -### 1.1.1 - -* [`feaea38`](https://github.com/buggerjs/node-inspect/commit/feaea385a981e6b72a8d99277fbf575c54e15fc6) **style:** Typo in comment - - -### 1.1.0 - -* [`c64155f`](https://github.com/buggerjs/node-inspect/commit/c64155faa552f71463842a26330aa5bcbfc31670) **feat:** repl command - - -### 1.0.0 - -* [`44c4c79`](https://github.com/buggerjs/node-inspect/commit/44c4c79af5a228ccfd8906f11409b2a33390b878) **chore:** Initial commit -* [`985873c`](https://github.com/buggerjs/node-inspect/commit/985873cfb97146b38480080f9907219c473f1f6f) **feat:** Launching the example works -* [`3d92d05`](https://github.com/buggerjs/node-inspect/commit/3d92d05cca152a2c2647aa64eefc80432638bc4d) **chore:** Proper license and passing tests -* [`b3f99d9`](https://github.com/buggerjs/node-inspect/commit/b3f99d981038b17663fcfd984d2f5d6d9b51ee18) **feat:** Futile attempts to send a valid ws frame -* [`465cfb7`](https://github.com/buggerjs/node-inspect/commit/465cfb7b295aebb48b285c26f6de9c4657fe590d) **feat:** Working ws connection -* [`da9f011`](https://github.com/buggerjs/node-inspect/commit/da9f01118e2b144f2da8cd370113a608526774a1) **fix:** Fix remote connect -* [`5ef33d7`](https://github.com/buggerjs/node-inspect/commit/5ef33d7892cc49becb4c66098fc7927bc74b014a) **feat:** Working step-by-step -* [`534e1e4`](https://github.com/buggerjs/node-inspect/commit/534e1e46b307d61d51eb4c0aab4a3b17c17aea3d) **chore:** Add bin entry -* [`8cff9cf`](https://github.com/buggerjs/node-inspect/commit/8cff9cfb0138b5ecff0f5f6a7839dbfddc0684fd) **style:** Use simpler key thingy -* [`720ec53`](https://github.com/buggerjs/node-inspect/commit/720ec53a5b251ab3caf27f06b60924efb9e03a92) **doc:** Add instructions -* [`b89ad60`](https://github.com/buggerjs/node-inspect/commit/b89ad601b885a417e6433b1609477d8453f498a1) **doc:** More helpful docs -* [`de9243c`](https://github.com/buggerjs/node-inspect/commit/de9243c95eabe733d05952229340808c3cebf129) **feat:** Watchers -* [`e16978f`](https://github.com/buggerjs/node-inspect/commit/e16978ff8e4b2b2bdccf88fd7d3905f525822981) **docs:** Working usage hints -* [`2dbc204`](https://github.com/buggerjs/node-inspect/commit/2dbc2042145fd97169fc7536186a449715e27810) **refactor:** Use proxies -* [`b8c9b14`](https://github.com/buggerjs/node-inspect/commit/b8c9b147713f63181396d5a7fe4c2f737b733b4c) **style:** Remove unused var -* [`f6b4b20`](https://github.com/buggerjs/node-inspect/commit/f6b4b20a1d28d91cfe452b995f7dbe5f7c749e89) **feat:** Nicer inspect of remote values -* [`36887c6`](https://github.com/buggerjs/node-inspect/commit/36887c66bbf26d540f087f80ddfec38462a33bdf) **fix:** Properly print watchers -* [`7729442`](https://github.com/buggerjs/node-inspect/commit/77294426157a28cc76e339cb13916a205182641e) **feat:** Add pause command -* [`e39a713`](https://github.com/buggerjs/node-inspect/commit/e39a7134873f06da37baaa9b6252cede4ad38d7a) **fix:** Properly format boolean properties -* [`f8f51d7`](https://github.com/buggerjs/node-inspect/commit/f8f51d7a01e8d74023306a08a3d6e2da63d123e1) **fix:** Properly format numeric properties -* [`89e6e08`](https://github.com/buggerjs/node-inspect/commit/89e6e087220f3c3cb628ac7541c44298485a2e04) **feat:** Add backtrace command -* [`82362ac`](https://github.com/buggerjs/node-inspect/commit/82362acfc7ce22b4cccc64889ec136dedc8895ec) **feat:** Add setBreakpoint() -* [`7064cce`](https://github.com/buggerjs/node-inspect/commit/7064ccec3b103683088d532abfe5b4e7c066948b) **feat:** Add `setBreakpoint(line)` -* [`360580e`](https://github.com/buggerjs/node-inspect/commit/360580eba4353e81311e56df018eec0ca233da11) **feat:** Add run/kill/restart -* [`b1b576e`](https://github.com/buggerjs/node-inspect/commit/b1b576e2645723a8575df544e0bfb672d60d9d91) **feat:** Add `help` command -* [`2db4660`](https://github.com/buggerjs/node-inspect/commit/2db46609cd1c8543d31ebd5dc47e4c27ec254841) **feat:** Add remaining sb() variants -* [`f2ad1ae`](https://github.com/buggerjs/node-inspect/commit/f2ad1aeedafb154043d70bb9195b10986d311d26) **fix:** Display breakpoints set into the future -* [`73272f9`](https://github.com/buggerjs/node-inspect/commit/73272f9ace1f8546f8cad1d53627dbffba50bb4e) **refactor:** Make breakpoints more inspect friendly -* [`507a71d`](https://github.com/buggerjs/node-inspect/commit/507a71de345a3de7fe144517e9f5ea264ff993e3) **feat:** Add breakpoints command -* [`5fb3e5d`](https://github.com/buggerjs/node-inspect/commit/5fb3e5d17bbcfd45b264431547b3cf0b781c7640) **docs:** Link to Command Line API docs -* [`81af501`](https://github.com/buggerjs/node-inspect/commit/81af501bbf85397e2078310c7f24a9ac5b7f02dc) **chore:** Fix license field diff --git a/deps/node-inspect/CONTRIBUTING.md b/deps/node-inspect/CONTRIBUTING.md deleted file mode 100644 index 012d29471462de..00000000000000 --- a/deps/node-inspect/CONTRIBUTING.md +++ /dev/null @@ -1,181 +0,0 @@ -# Contributing - -🎉🏅 Thanks for helping us improve this project! 🙏 - -This document outlines some of the practices we care about. -If you have any questions or suggestions about the process, -feel free to [open an issue](#reporting-issues). - -## Code of Conduct - -The [Node.js Code of Conduct][] applies to this repo. - -[Node.js Code of Conduct]: https://github.com/nodejs/node/blob/master/CODE_OF_CONDUCT.md - -## Governance - -This project falls under the governance of the Node.js Diagnostics WG as -described at . - -## Developer's Certificate of Origin 1.1 - -By making a contribution to this project, I certify that: - -* (a) The contribution was created in whole or in part by me and I - have the right to submit it under the open source license - indicated in the file; or - -* (b) The contribution is based upon previous work that, to the best - of my knowledge, is covered under an appropriate open source - license and I have the right under that license to submit that - work with modifications, whether created in whole or in part - by me, under the same open source license (unless I am - permitted to submit under a different license), as indicated - in the file; or - -* (c) The contribution was provided directly to me by some other - person who certified (a), (b) or (c) and I have not modified - it. - -* (d) I understand and agree that this project and the contribution - are public and that a record of the contribution (including all - personal information I submit with it, including my sign-off) is - maintained indefinitely and may be redistributed consistent with - this project or the open source license(s) involved. - -## How Can I Contribute? - -### Reporting Issues - -If you find any mistakes in the docs or a bug in the code, -please [open an issue in Github](https://github.com/nodejs/node-inspect/issues/new) so we can look into it. -You can also [create a PR](#contributing-code) fixing it yourself of course. - -If you report a bug, please follow these guidelines: - -* Make sure the bug exists in the latest version. -* Include instructions on how to reproduce the issue. - The instructions should be as minimal as possible - and answer the three big questions: - 1. What are the exact steps you took? This includes the exact versions of node, npm, and any packages involved. - 1. What result are you expecting? - 1. What is the actual result? - -### Improving Documentation - -For small documentation changes, you can use [Github's editing feature](https://help.github.com/articles/editing-files-in-another-user-s-repository/). -The only thing to keep in mind is to prefix the commit message with "docs: ". -The default commit message generated by Github will lead to a failing CI build. - -For larger updates to the documentation -it might be better to follow the [instructions for contributing code below](#contributing-code). - -### Contributing Code - -**Note:** If you're planning on making substantial changes, -please [open an issue first to discuss your idea](#reporting-issues). -Otherwise you might end up investing a lot of work -only to discover that it conflicts with plans the maintainers might have. - -The general steps for creating a pull request are: - -1. Create a branch for your change. - Always start your branch from the latest `master`. - We often prefix the branch name with our initials, e.g. `jk-a-change`. -1. Run `npm install` to install the dependencies. -1. If you're fixing a bug, be sure to write a test *first*. - That way you can validate that the test actually catches the bug and doesn't pass. -1. Make your changes to the code. - Remember to update the tests if you add new features or change behavior. -1. Run the tests via `npm test`. This will also run style checks and other validations. - You might see errors about uncommitted files. - This is expected until you commit your changes. -1. Once you're done, `git add .` and `git commit`. - Please follow the [commit message conventions](#commits--commit-messages) described below. -1. Push your branch to Github & create a PR. - -#### Code Style - -In addition to any linting rules the project might include, -a few general rules of thumb: - -* Try to match the style of the rest of the code. -* We prefer simple code that is easy to understand over terse, expressive code. -* We try to structure projects by semantics instead of role. - E.g. we'd rather have a `tree.js` module that contains tree traversal-related helpers - than a `helpers.js` module. -* Actually, if you create helpers you might want to put those into a separate package. - That way it's easier to reuse them. - -#### Commits & Commit Messages - -Please follow the [angular commit message conventions](https://github.com/angular/angular.js/blob/master/CONTRIBUTING.md#-git-commit-guidelines). -We use an automated tool for generating releases -that depends on the conventions to determine the next version and the content of the changelog. -Commit messages that don't follow the conventions will cause `npm test` (and thus CI) to fail. - -The short summary - a commit message should look like this: - -``` -: - - - - - -