lib: brand-check Navigator getters to throw ERR_INVALID_THIS#63601
lib: brand-check Navigator getters to throw ERR_INVALID_THIS#636013zrv wants to merge 3 commits into
Conversation
Fixes: nodejs#63513 Signed-off-by: Mohamed Sayed <k@3zrv.com>
|
Review requested:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #63601 +/- ##
=========================================
Coverage 90.32% 90.33%
=========================================
Files 730 732 +2
Lines 234669 236513 +1844
Branches 43946 44542 +596
=========================================
+ Hits 211967 213656 +1689
- Misses 14417 14580 +163
+ Partials 8285 8277 -8
🚀 New features to boost your workflow:
|
|
I don't think adding a check is worth it, I think the current behavior is fine actually, the spec requires a TypeError, we're throwing a TypeError (except for |
LiviaMedeiros
left a comment
There was a problem hiding this comment.
+1 on explicit ERR_INVALID_THIS over implicit private field access. Errors from private fields are misleading and not future-proof: it's too easy to break 'implicit throw' unintentionally (in fact, Navigator.prototype.language was initially introduced using private field, too).
It’s only true if that’s not covered by tests (which I would have expected WPT to cover, but I guess not, or at least not the subset we’re running) |
There was a problem hiding this comment.
In undici we are lenient with errors too with the expectation that a reviewer would notice if a change similar to the one that changed .language was made.
Since it's not reasonable here, I think the change is fine. Regarding the WPTs, brand checks should be implemented the same across globals in most platforms so the assumption is that if you have it implemented properly in one spec, it's also implemented correctly in the thousands of over browser globals.
Signed-off-by: Mohamed Sayed <k@3zrv.com>
|
Thanks for the reviews, the test now covers all getters via I'm more into keeping the explicit |
|
Here's what the error looks like on the browser side:
FWIW I'm in the Chromium camp, I think minimal effort is the appropriate amount of support we should spend on "passing an invalid |
|
are we still good to merge this? missing anything? @aduh95 @KhafraDev @LiviaMedeiros |
| * @returns {number} | ||
| */ | ||
| get hardwareConcurrency() { | ||
| if (!(#availableParallelism in this)) throw new ERR_INVALID_THIS('Navigator'); |
There was a problem hiding this comment.
We explicitly don't do this and rely on private properties for brand validation. This is intentional.
There was a problem hiding this comment.
I was previously neutral until I read #63601 (review), which I think is fair. There's already been a regression due to using private properties for brand checks and the more uniform error message is a plus.
There was a problem hiding this comment.
I understand that it's intentional, but the .language regression (introduced as a non-private getter, which silently broke the brand check) is exactly the failure mode that intent didn't survive. The fact that nothing in the class declaration or in CI flagged it is what concerns me about relying on private-field access as the brand-check mechanism.
If you still feel strongly, I can scope the PR down to just fixing .language and rely on the new prototype-iterating test to catch the next regression. But given the reviews, I'd prefer to keep the explicit checks.
@anonrig
There was a problem hiding this comment.
There's already been a regression due to using private properties
Using a custom error code does not protect against that, it's orthogonal. Having coverage protect against that, regardless how we do the brand check.
There was a problem hiding this comment.
Scoped down per the discussion. The PR now only adds an explicit brand check to .language, and leaves the other getters relying on the private-field throw as before.
There was a problem hiding this comment.
Using a custom error code does not protect against that
Well yeah, but now there are 2 separate error messages thrown (the brand check for navigator.language and the brand checks for everything else.
The issue linked believed that the v8 error was an "internal [implementation] error", which changing 1 error won't fix either. Ultimately, the v8 error isn't clear and doesn't convey the expected behavior.
, so I'm not keen on adding a if that will slow down the happy path
Tbh we probably shouldn't be implementing web specs if a single if statement is a cause for concern.
Signed-off-by: Mohamed Sayed <k@3zrv.com>
| // `language` does not read a private field, so brand-check explicitly | ||
| // to keep parity with the other getters when called on a non-Navigator | ||
| // receiver (e.g. `Navigator.prototype.language`). | ||
| if (!(#languages in this)) throw new ERR_INVALID_THIS('Navigator'); |
There was a problem hiding this comment.
We shouldn't do this. We explicitly avoided doing this because of performance in the past. We went through deprecation cycles multiple times because of this.
Fixes: #63513
Add an explicit
#field in thisbrand check to each getter so a proper ERR_INVALID_THIS is thrown, matching browser behavior. This also fixeslanguage, which previously did not error at all on the prototype because it did not touch a private field.