Skip to content

Commit

Permalink
util: prevent leaking internal properties
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
BridgeAR committed Feb 16, 2019
1 parent 2867425 commit dd1a712
Show file tree
Hide file tree
Showing 3 changed files with 26 additions and 6 deletions.
4 changes: 4 additions & 0 deletions doc/api/util.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 6 additions & 2 deletions lib/internal/util/inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)}`);
}
}
}
Expand Down
20 changes: 16 additions & 4 deletions test/parallel/test-util-inspect.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 });

Expand Down Expand Up @@ -1584,7 +1596,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.]'));
}
Expand Down

0 comments on commit dd1a712

Please sign in to comment.