-
-
Notifications
You must be signed in to change notification settings - Fork 33.8k
util: safely inspect getter errors whose message throws #60684
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
base: main
Are you sure you want to change the base?
Conversation
|
Note that I based the behaviour from @legendecas comment in this related PR: #60139 (review)
|
cff9e6a to
ab97c2a
Compare
ab97c2a to
09d8f0b
Compare
lib/internal/util/inspect.js
Outdated
| let messageSuffix; | ||
| try { | ||
| // Error message itself may be a getter | ||
| messageSuffix = ` (${err.message})`; | ||
| } catch { | ||
| messageSuffix = ''; | ||
| } | ||
| const message = `<Inspection threw${messageSuffix}>`; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
wdyt of doing this instead?
| let messageSuffix; | |
| try { | |
| // Error message itself may be a getter | |
| messageSuffix = ` (${err.message})`; | |
| } catch { | |
| messageSuffix = ''; | |
| } | |
| const message = `<Inspection threw${messageSuffix}>`; | |
| let message = '<Inspection threw>'; | |
| if (isErrorStackTraceLimitWritable()) { | |
| const stackTraceLimit = Error.stackTraceLimit; | |
| Error.stackTraceLimit = 0; | |
| try { message = `<Inspection threw (${inspect(err)})>`; } | |
| catch {} | |
| finally { Error.stackTraceLimit = stackTraceLimit; } | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This way the "Inspection threw" text is in two places, which seems strictly worse to me
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The suggestion is not about messageSuffix, it's about using inspect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we first agree on the behavior? Any value that is thrown and has a message property which is a string will be displayed as the "inspection threw" detail.
I’ve currently implemented a typeof message === "string" check, should we also consider testing other types, or just display the value as-is (excluding null and undefined)?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My suggestion is to use inspect(err) (or at least, reuse the logic from another function in this file) instead of introducing ad-hoc checks that are not consistent with the rest of codebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ok I've committed with messageSuffix to avoid duplicating "Inspection threw" text
test/parallel/test-util-inspect.js
Outdated
| { | ||
| const error = { | ||
| // The message itself is a getter that throws | ||
| get message() { throw new Error('Oops'); } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you add test cases for throwing null and other uncommon values?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added throwing null, undefined, {}, true, Error can you think about something else? 🤔
test/parallel/test-util-inspect.js
Outdated
| // Heh? I don't know how to override the error stakc to make it predictable | ||
| ' [Symbol(Symbol.species)]: ' + | ||
| "[Getter: <Inspection threw (TypeError: Symbol.prototype.toString requires that 'this' be a Symbol\n" + | ||
| ' at Bar.toString (<anonymous>)\n' + | ||
| ' at formatPrimitive (node:internal/util/inspect:2246:13)\n' + | ||
| ' at formatProperty (node:internal/util/inspect:2556:29)\n' + | ||
| ' at addPrototypeProperties (node:internal/util/inspect:1010:21)\n' + | ||
| ' at getConstructorName (node:internal/util/inspect:918:11)\n' + | ||
| ' at formatRaw (node:internal/util/inspect:1194:23)\n' + | ||
| ' at formatValue (node:internal/util/inspect:1184:10)\n' + | ||
| ' at formatProperty (node:internal/util/inspect:2536:11)\n' + | ||
| ' at formatRaw (node:internal/util/inspect:1429:9)\n' + | ||
| ' at formatValue (node:internal/util/inspect:1184:10))>]\n' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hum, do you know if it's because isErrorStackTraceLimitWritable() returns false, or if it's because the stack was computed before we try to set stackTraceLimit to 0? In any case, if that's indeed the output, we can use RegExp.escape and assert.match to validate only what we need (i.e. not the line numbers of internal modules)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like Error.stackTraceLimit = 0; in implementation does not work and the whole stack is returned everytime 🤔 In my tests (an potentially in real cases) errors are created before being thrown.
See other tests: https://github.com/yvele/node/blob/9b05e4ee82d3627deb9647c094a315610f1cc855/test/parallel/test-util-inspect.js#L2597-L2608
assert.strictEqual(
inspect(thrower, { getters: true }),
'{\n' +
' foo: [Getter: <Inspection threw (Error: Oops\n' +
' at get foo (/foo/node_modules/foo.js:2:7)\n' +
' at get bar (/foo/node_modules/bar.js:827:30))>]\n' +
'}',
);Also stackTraceLimit is serialized https://github.com/yvele/node/blob/9b05e4ee82d3627deb9647c094a315610f1cc855/test/parallel/test-util-inspect.js#L2653-L2662
assert.strictEqual(
inspect({
get foo() { throw Error; }
}, { getters: true }),
'{\n' +
' foo: [Getter: <Inspection threw ([Function: Error] { stackTraceLimit: 0 })>]\n' +
'}'
);Also, why not returning the whole stack? Indentation seems to work
89f0e53 to
9b05e4e
Compare
Fixes: #60683