Skip to content
Permalink
Browse files

util: prevent leaking internal properties

This prevents leaking of the internal `inspect()` properties when
using a custom inspect function.

It also aligns the indentation to the way it was in v8.0.0 since
that changed unintentionally. All strings returned by the custom
inspect function will now be indented appropriately to the current
depth.

PR-URL: #24971
Refs: #24765
Reviewed-By: Gus Caplan <me@gus.host>
Reviewed-By: Anna Henningsen <anna@addaleax.net>
Reviewed-By: Rich Trott <rtrott@gmail.com>
  • Loading branch information...
BridgeAR committed Dec 11, 2018
1 parent be78266 commit 7b674697d8005c29391ebaaf562eb4d92ed9b129
Showing with 26 additions and 6 deletions.
  1. +4 −0 doc/api/util.md
  2. +6 −2 lib/internal/util/inspect.js
  3. +16 −4 test/parallel/test-util-inspect.js
@@ -388,6 +388,10 @@ stream.write('With ES6');
<!-- YAML
added: v0.3.0
changes:
- version: REPLACEME
pr-url: https://github.com/nodejs/node/pull/24971
description: Internal properties no longer appear in the context argument
of a custom inspection function.
- version: v11.7.0
pr-url: https://github.com/nodejs/node/pull/25006
description: ArrayBuffers now also show their binary contents.
@@ -516,18 +516,22 @@ function formatValue(ctx, value, recurseTimes, typedArray) {
maybeCustom !== inspect &&
// Also filter out any prototype objects using the circular check.
!(value.constructor && value.constructor.prototype === value)) {
// Remove some internal properties from the options before passing it
// through to the user function. This also prevents option manipulation.
// eslint-disable-next-line no-unused-vars
const { budget, seen, indentationLvl, ...plainCtx } = ctx;
// This makes sure the recurseTimes are reported as before while using
// a counter internally.
const depth = ctx.depth === null ? null : ctx.depth - recurseTimes;
const ret = maybeCustom.call(value, depth, ctx);
const ret = maybeCustom.call(value, depth, plainCtx);
// If the custom inspection method returned `this`, don't go into
// infinite recursion.
if (ret !== value) {
if (typeof ret !== 'string') {
return formatValue(ctx, ret, recurseTimes);
}
return ret;
return ret.replace(/\n/g, `\n${' '.repeat(ctx.indentationLvl)}`);
}
}
}
@@ -775,9 +775,21 @@ util.inspect({ hasOwnProperty: null });
assert.strictEqual(util.inspect(subject), "{ foo: 'bar' }");
subject[util.inspect.custom] = (depth, opts) => {
assert.strictEqual(opts.customInspectOptions, true);
};
subject[util.inspect.custom] = common.mustCall((depth, opts) => {
const clone = { ...opts };
// This might change at some point but for now we keep the stylize function.
// The function should either be documented or an alternative should be
// implemented.
assert.strictEqual(typeof opts.stylize, 'function');
assert.strictEqual(opts.seen, undefined);
assert.strictEqual(opts.budget, undefined);
assert.strictEqual(opts.indentationLvl, undefined);
assert.strictEqual(opts.showHidden, false);
opts.showHidden = true;
return { [util.inspect.custom]: common.mustCall((depth, opts2) => {
assert.deepStrictEqual(clone, opts2);
}) };
});
util.inspect(subject, { customInspectOptions: true });
@@ -1593,7 +1605,7 @@ util.inspect(process);
);
const longList = util.inspect(list, { depth: Infinity });
const match = longList.match(/next/g);
assert(match.length > 1000 && match.length < 10000);
assert(match.length > 500 && match.length < 10000);
assert(longList.includes('[Object: Inspection interrupted ' +
'prematurely. Maximum call stack size exceeded.]'));
}

0 comments on commit 7b67469

Please sign in to comment.
You can’t perform that action at this time.