-
Notifications
You must be signed in to change notification settings - Fork 30.1k
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
"[Object: null prototype]" spam from util.inspect #27001
Comments
The commit itself also seems overly complicated to me. Why is it checking for a |
It’s not exclusive: > a = new Map([[1,2],[3,4]]); Object.setPrototypeOf(a, null)
[Map: null prototype] { 1 => 2, 3 => 4 }
> a.set
undefined That being said – it’s unlikely to happen in the real world. I don’t have strong opinions about whether or how to include this information in the /cc @BridgeAR |
Yikes, sometimes I forget how horrifying javascript can be. But yeah, noone would do this in real-world code (I'd hope!), as opposed to |
it only adds extra output to things that actually have a null prototype, and as you say, its rather rare, so perhaps not a huge issue? |
I said no such thing, and if I didn't consider it an issue then I wouldn't have opened one. Using a null-prototype for objects is common good practice in certain cases (basically whenever it is used kind of like a Map, but using an actual Map would just be more cumbersome and less programmer-friendly than using an object). The For example, this update turned this debug dump in a test script:
into
This is simply an eyesore. (In contrast, creating a Set/Map/Array/TypedArray and then manually changing the prototype to |
@mvduin we provide the prototype for all objects. Doing the same for the Examples how the output behaves for different prototypes: class Foo {}
const a = {}
Object.setPrototypeOf(a, Foo.prototype)
console.log(a)
// Foo {} I personally suggest to give the > util.inspect.replDefaults.compact = 3
3
> keydb
{
host: [Object: null prototype] {
key: '159355cb40dc15c987e7830c77c98fd47d437fdae9ad51787333f0da97e38a7d'
},
product: [Object: null prototype] {
key: '4b038d142de2a5453e1ea15e558115077dc208477a5447508f3990e839073f44',
authority: 'product'
},
root: [Object: null prototype] {
key: 'a7a4b0c777a880e7d77a715d07fefad75bbfd194e51735bc2c247ba52de9390d',
authority: 'root'
},
test: [Object: null prototype] {
key: 'a7299d4c99ec31474513fc39f407521ff388ca5d830a1f2a7a1aed71d302f7bd',
authority: 'root'
},
'u:test': [Object: null prototype] {
key: 'e78299c54a9e3c2b55adc2fff0f794d447f8737b181a9f57fecbd7ba8d715aa7',
authority: 'user'
}
}
As a personal request: it would be nice if you would try to provide your feedback in a more constructive way that does not decrease the value of other persons work. |
👍 yes please. @mvduin hey 👋 Please be more considerate when you interact here. Please consider self moderating the below:
In addition, I would recommend considering toning down the criticism in your messages and focus on objective technical aspects of the issue. Please refer to https://github.com/nodejs/admin/blob/master/CODE_OF_CONDUCT.md for a brief guide on interaction in the org. If you would like to discuss this in private feel free to reach out via report@nodejs.org or moderation@nodejs.org Thanks for the issue, I think this discussion is worth having and I'd like us to figure out a way to avoid |
(wearing my moderator hat)
To echo and amplify a little, yes, there are definitely warts to JavaScript, especially around prototype handling, but #22141 is an issue that can be solved a number of ways, none of which are obviously "most" correct. It seems like this conversation is headed towards an OK resolution, but still – can we keep the conversation focused on pros and cons, and spend less time talking about aesthetics, which are inherently subjective? |
I'm tagging this 'feature request'. I think the consensus is that in general it's a good change and unlikely to simply be reverted. (FWIW, I feel the same way.) If someone doesn't come up with a good counterproposal in the next few days, I'll close this out. |
for null prototype: |
Apologies for my ill chosen words. I just got really annoyed when, after applying some updates to have the latest security fixes, I was suddenly faced with this rather verbose output in my previously lean and clean debug output. Posting while in a state of annoyance is rarely a good idea.
Done. I've edited my posts to tone them down a bit.
But there are limits to what it can do regardless, and it's still easy to find cases where The new output also seems rather inconsistent to me. In general
In a rare few cases it also emphasizes that an object is an instance of some specific base class that is regarded as being important (e.g. Promise or Set), when it doesn't match the constructor name:
|
What would you suggest for a null-prototype Map or Set or other object? (I’m going to be making these same changes in https://npmjs.com/object-inspect, to follow whatever the conclusion is here) |
I honestly don't think they are a relevant case to consider, and I'm not sure it even makes sense to consider these to be Maps or Sets since they are not instances of these classes, even if they have the relevant hidden slots. I'd be fine with them being rendered as I was curious to see how
|
The slots are entirely what makes them maps or sets, not their prototype chain :-) you’ve found what i consider a bug in util.inspect tho! So if a set is normally |
I mean, technically yes, but for most practical purposes that's an implementation detail. The only way the average javascript programmer can test whether a value is a Set is using Also, using the hidden slots rather than prototype chain seems inconsistent with other behaviour of
Here it's highlighting this object as being a
Either that or actually just Mostly though, I'd just go with whatever is the least effort, since I don't think it matters how these abominations are rendered ;-) |
Thank you.
This is not about
It is about consistency and to prevent tampering. This is especially important in JS where it's possible to manipulate everything. So there's definitely a use case.
That is not correct. It just prints the
That is outdated. On master it prints
I definitely want to know about tampered objects in my logs. It is not about how I personally create objects, it's about input in general, no matter from what source.
This is not intuitive for me (and I expect to others as well but I can only speak for myself). As a reader, I would expect this output to be a bug and not that it's about the
It is a best effort for most inputs. I personally think your examples all come out fine but there is no absolute right or wrong. So far all additions to
That would cause "regular" objects to be more verbose than they are currently.
I personally would not know what this stands for. And how should it look like for other classes? |
That is not correct
That would not be distinguishable from a lot of other types.
The current implementation is more complex for |
Ah, I stand corrected. I looked for it in
You've used the word "tampering" before but I have no idea what you're referring to. Who is tampering with what, and what are they doing in my nodejs application? Every npm module I use is (unfortunately) implicitly trusted anyway, since they can execute arbitrary code as part of being installed by npm. I have trouble imagining what kind of tampering would involve passing me objects with an oddball prototype.
Either should be fine if you're not doing anything with multiple contexts. This is probably more a worry when doing web programming, yet in that case
I know, but I very much doubt it matters in this case. There are numerous ways anyway in which objects are not necessarily distinguishable based on |
But you'd figure it out quickly. The current Anyway, it seems that using a null-prototype object as prototype (instead of null itself) is an effective workaround:
so I guess I'll just start using that instead of |
Let's say you write your code on Node latest and deploy it on Node 8 (LTS). You tested it and everything works. Unfortunately one of your npm dependencies has a dependency that detects Node's version and shims some newer Node feature (let's say: worker_threads, some http2 change or a new crypto method). That shim for compatibility replaces Now, I wish polyfills wouldn't do this but it's also a pretty common things. We've had polyfills (like for WeakMap) that altered Now as Node core and an open source library maintainer this is something we care about a lot since we use "the same JavaScript" too. I've had bugs related to some user changing some builtin in virtually any open source library I maintain. Now, you might say that for the average app developer it's not a huge deal and that proper tests would catch the above example and you would be right. I'm on the fence with regards to how we should log prototypes and I'd like to see better behaviour than what we currently do.
I think this was discussed a few times (detecting the same object type across realms). I think @ljharb even had a proposal for isError at some point (what happened to that?). Most of the work on those proposal is blocked on actually doing the work, lobbying and reaching consensus in tc39. I encourage you to reach out to specification bodies (we're lucky to have several tc39 members around) and ask how you can get involved.
Absolutely, echoing @bnoordhuis I think what we need right now is a counter-proposal that maintains correctness but has less verbose output. |
Error.isError was rejected; the committee isn’t fond of brand-checking, by and large, and Error remains the only builtin that doesn’t provide one - the stacks proposal, however, will provide one. Brand checks remain very important, and i have a number of packages in npm that work in both browsers and node to perform them. |
They are not. Only use the ones exposed by
That's not what I call a good API. Things should feel natural without having to look up what things stand for.
It is still an object, even if it has a null prototype. It's also a big difference if the prototype is set on e.g., a Set or a "plain" Object. It is possible to do things in JS that do not seem "right" but a lot of code contains things that "do not seem right". It's therefore important to tell the user what builtin was used before the prototype was set to
Newer Node.js versions log the prototype in these cases as well, so I recommend against it.
That is what I call "tampering" with code: any developer in a team or a module might do things on the prototype or with what ever objects. It could be a team mate or a bug that causes the prototype to be manipulated as security vector while parsing incoming
Visualizing the prototype for special cases should not be a main factor for log output.
That seems out of scope for this issue. |
Did you struggle with the output so far and have you tried the It is not less verbose but the formatting is improved. I personally like the current intuitive null prototype description and I personally can not think of an alternative that would be as good. Thus I am hesitant about changing something in that direction. |
Honestly I'm not too bothered by it since I haven't run into an issue with the current method "organically" myself. I can of course create a case where it is more verbose but 🤷♂️
I can't think of one either - that's not to say there isn't a better alternative we just haven't thought of yet. I was mostly saying this to reiterate that a better proposal is what's currently blocking improving this (rather than say... code).
that's a shame, thank you for fighting the good fight and trying to promote these things :) 🙇 |
As @bnoordhuis pointed out most people seem to actually agree with the change and there was no further comment for quite a while. Thus, I'll close this issue. If there's another good alternative, please feel free to comment so that this can be reopened. |
Commit 90014b6 changed
util.inspect
as a fix for #22141. While it may be important to emphasize null-prototype objects for that very particular use-case, for general debugging it is just annoying spam that can make dumps of complex objects substantially less readable. This should not be the default behaviour, but an option specifically enabled byassert.deepStrictEqual
's use of inspect.The text was updated successfully, but these errors were encountered: