Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

util: fix circular ref for Set and Map #14775

Closed
wants to merge 1 commit into from

Conversation

BridgeAR
Copy link
Member

Fixes #14758

Checklist
  • make -j4 test (UNIX), or vcbuild test (Windows) passes
  • tests and/or benchmarks are included
  • documentation is changed or added
  • commit message follows commit guidelines
Affected core subsystem(s)

util

@nodejs-github-bot nodejs-github-bot added the util Issues and PRs related to the built-in util module. label Aug 11, 2017
var str = formatValue(ctx, v, nextRecurseTimes);
var str = ctx.seen.includes(v) ?
ctx.stylize('[Circular]', 'special') :
formatValue(ctx, v, nextRecurseTimes);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don’t know if you tried that, but wouldn’t it be better to do this type of check/early return in formatValue, before the ctx.seen.push() call (i.e. if (ctx.seen.includes(v)) return ctx.stylize('[Circular]', 'special');)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If not: Can we DRY this up a bit, maybe add a function for it or something?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@not-an-aardvark @BridgeAR @aqrln This is what I was having in mind:

diff in the fold
diff --git a/lib/util.js b/lib/util.js
index a9f267bd416d..9b8e8395ffac 100644
--- a/lib/util.js
+++ b/lib/util.js
@@ -216,7 +216,7 @@ function debuglog(set) {
 function inspect(obj, opts) {
   // default options
   var ctx = {
-    seen: [],
+    seen: new Set(),
     stylize: stylizeNoColor
   };
   // legacy...
@@ -613,11 +613,16 @@ function formatValue(ctx, value, recurseTimes) {
     }
   }
 
-  ctx.seen.push(value);
+  var output;
+  if (ctx.seen.has(value)) {
+    output = ctx.stylize('[Circular]', 'special');
+  } else {
+    ctx.seen.push(value);
 
-  var output = formatter(ctx, value, recurseTimes, visibleKeys, keys);
+    output = formatter(ctx, value, recurseTimes, visibleKeys, keys);
 
-  ctx.seen.pop();
+    ctx.seen.pop();
+  }
 
   return reduceToSingleString(output, base, braces, ctx.breakLength);
 }
@@ -822,21 +827,17 @@ function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
     }
   }
   if (!str) {
-    if (ctx.seen.indexOf(desc.value) < 0) {
-      if (recurseTimes === null) {
-        str = formatValue(ctx, desc.value, null);
+    if (recurseTimes === null) {
+      str = formatValue(ctx, desc.value, null);
+    } else {
+      str = formatValue(ctx, desc.value, recurseTimes - 1);
+    }
+    if (str.indexOf('\n') > -1) {
+      if (array) {
+        str = str.replace(/\n/g, '\n  ');
       } else {
-        str = formatValue(ctx, desc.value, recurseTimes - 1);
+        str = str.replace(/^|\n/g, '\n   ');
       }
-      if (str.indexOf('\n') > -1) {
-        if (array) {
-          str = str.replace(/\n/g, '\n  ');
-        } else {
-          str = str.replace(/^|\n/g, '\n   ');
-        }
-      }
-    } else {
-      str = ctx.stylize('[Circular]', 'special');
     }
   }
   if (name === undefined) {

WDYT?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am aware of that (ref #14492 (comment)) but I would rather keep the concerns separated.
And I am actually working on improving the inspect performance in general at the moment and I think it would be best to keep the performance changes in that one but I did not yet have enough time to finish it.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@addaleax That would be a semver-major change as the ctx is passed to custom inspection functions.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One non-breaking workaround would be to continue to make context.seen an array and create a new Set internally, and use the Set for all membership checks. That way we would sill avoid linear-time membership checks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I’ll just open a PR and we can discuss from there.

@@ -738,7 +738,9 @@ function formatSet(ctx, value, recurseTimes, visibleKeys, keys) {
var output = [];
value.forEach(function(v) {
var nextRecurseTimes = recurseTimes === null ? null : recurseTimes - 1;
var str = formatValue(ctx, v, nextRecurseTimes);
var str = ctx.seen.includes(v) ?
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This isn't directly related to this PR, but why is ctx.seen an array? Would it be better to use a Set/WeakSet to avoid linear-time includes checks?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@BridgeAR
Copy link
Member Author

Closing in favor of #14790

@BridgeAR BridgeAR closed this Aug 13, 2017
addaleax pushed a commit to addaleax/node that referenced this pull request Aug 17, 2017
Ref: nodejs#14775
PR-URL: nodejs#14790
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Evan Lucas <[email protected]>
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Yuta Hiroto <[email protected]>
Reviewed-By: Alexey Orlenko <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
addaleax pushed a commit that referenced this pull request Aug 17, 2017
Ref: #14775
PR-URL: #14790
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Evan Lucas <[email protected]>
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Yuta Hiroto <[email protected]>
Reviewed-By: Alexey Orlenko <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
MylesBorins pushed a commit that referenced this pull request Sep 10, 2017
Ref: #14775
PR-URL: #14790
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Evan Lucas <[email protected]>
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Yuta Hiroto <[email protected]>
Reviewed-By: Alexey Orlenko <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
MylesBorins pushed a commit that referenced this pull request Sep 12, 2017
Ref: #14775
PR-URL: #14790
Reviewed-By: Refael Ackermann <[email protected]>
Reviewed-By: James M Snell <[email protected]>
Reviewed-By: Evan Lucas <[email protected]>
Reviewed-By: Timothy Gu <[email protected]>
Reviewed-By: Colin Ihrig <[email protected]>
Reviewed-By: Tobias Nießen <[email protected]>
Reviewed-By: Yuta Hiroto <[email protected]>
Reviewed-By: Alexey Orlenko <[email protected]>
Reviewed-By: Anna Henningsen <[email protected]>
@BridgeAR BridgeAR added the invalid Issues and PRs that are invalid. label Sep 14, 2017
@BridgeAR BridgeAR deleted the fix-circular-ref branch April 1, 2019 23:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
invalid Issues and PRs that are invalid. util Issues and PRs related to the built-in util module.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

util.inspect not checking for loops in {,Weak}Map data
6 participants