Closed Bug 1803800 Opened 2 years ago Closed 2 years ago

Stop using __proto__ in Firefox code

Categories

(Firefox :: General, defect)

Desktop
All
defect

Tracking

()

RESOLVED FIXED
110 Branch
Tracking Status
firefox-esr102 --- wontfix
firefox108 --- wontfix
firefox109 --- wontfix
firefox110 --- fixed

People

(Reporter: Gijs, Assigned: Gijs)

References

Details

(Keywords: sec-want, Whiteboard: [post-critsmash-triage][adv-main110-])

Attachments

(7 files)

For context, see bug 1770057.

Keywords: sec-want
Assignee: nobody → gijskruitbosch+bugs
Status: NEW → ASSIGNED
Attached file Bug 1803800, r?markh!
Attached file Bug 1803800, r?mak

Depends on D163931

Attached file Bug 1803800, r?mak

Depends on D163932

Unfortunately lazy script getters load the file once for each accessed symbol, which
redeclares "let" and "const" and "class" variables, which was a problem here. But also,
loading the file multiple times is bad for performance (it is not a module so we
actually reload it) and the "lazy" variables get dereferenced immediately from
markup that is present both in browser.xhtml and the hidden window on macOS, so I
doubt lazy loading was getting us anything performance-wise.

This patch simplifies things by 'just' loading the file from the markup.

Depends on D163933

Depends on D163934

Attached file Bug 1803800, r?pbz
Attachment #9306848 - Attachment description: Bug 1803800 - remove __proto__ use in services/ code, r?markh!,leplatrem! → Bug 1803800, r?markh!
Attachment #9306849 - Attachment description: Bug 1803800 - remove __proto__ use in browser downloads code, r?mak → Bug 1803800, r?mak
Attachment #9306850 - Attachment description: Bug 1803800 - switch to real classes for Places views, r?mak → Bug 1803800, r?mak
Attachment #9306852 - Attachment description: Bug 1803800 - fix miscellaneous other toolkit __proto__ users, r?pbz!,sgalich! → Bug 1803800, r?pbz!,sgalich!
Attachment #9306880 - Attachment description: Bug 1803800 - fix PermissionsUI to not use __proto__, r?pbz → Bug 1803800, r?pbz
Group: firefox-core-security → core-security-release

I don't understand the motivation for this change. It seems like most of the __proto__ replacements here actually make things worse.

Maybe it isn't really obvious from the other bugs, but __proto__ inside an object literal is not a setter. If we remove the Object.prototype.__proto__ getter/setter in the future those uses will still work. Unless the value on the right can be controlled it should even be preferred over changing the [[Prototype]] later using the Object.setPrototypeOf function. (I think most of the old performance issues with that were fixed though)

Flags: needinfo?(gijskruitbosch+bugs)
Regressions: 1805678

(In reply to Tom Schuster (MoCo) from comment #9)

I don't understand the motivation for this change. It seems like most of the __proto__ replacements here actually make things worse.

That's quite a sweeping claim; it would be useful if you clarified how "most" changes here make things worse.

Maybe it isn't really obvious from the other bugs, but __proto__ inside an object literal is not a setter.

It wasn't obvious, no. Peter did remind me once I had finished writing all the patches you see on this bug and put them up. We had a brief discussion about what to do, in which my impression was that there was no strong reason to prefer __proto__ inside the literal over setPrototypeOf. Given that the patches were written, and did make finding remaining __proto__ cases much easier with simple searchfox queries, and in some cases switched to using class which is probably what we want to do longer term for readability/maintainability/documentation reasons anyway, I chose to continue getting to the point of landing this patchset. I did note this on the bigger review request that was still outstanding at the time (https://phabricator.services.mozilla.com/D163931#5388780) and left the choice to the reviewer.

I would have preferred to just switch everything to class immediately, but I ran into enough issues doing that just with the places code (there are implications around how super works, and how initialization of this works vs. ordering of constructors in the class/prototype chain, as well as plain lexical declaration, that broke a number of existing assumptions in the code) that I ended up postponing that kind of change for the other modules touched. We are likely to still do that kind of refactoring in other, non-security bugs though, e.g. bug 1804264.

If we remove the Object.prototype.__proto__ getter/setter in the future those uses will still work. Unless the value on the right can be controlled it should even be preferred over changing the [[Prototype]] later using the Object.setPrototypeOf function. (I think most of the old performance issues with that were fixed though)

I'm having trouble parsing this - it sounds like you're both saying that there won't be a perf difference anymore and that we should still prefer the "old" way of doing this, despite the fact that I can't even read the documentation for __proto__ on MDN without scrolling, because my entire screen is filled with red warnings saying "do not use this" and explicitly recommending getPrototypeOf and setPrototypeOf instead.

If it's really the case that using __proto__ in an object literal is objectively better, then we can try reverting some of the patches here in a separate bug, but then we should probably also revisit that documentation...

Finally, I'll note that I would say most of the code changed here is not hot/performance-sensitive in any way, perhaps being run once per window (and in fact, the places code is now generally being run fewer times...). The exception is the sync code, I think. I doubt that we have existing infrastructure that measures its performance, but if you think that this might have caused a serious performance regression there, let's file a follow-up bug and investigate that?

Flags: needinfo?(gijskruitbosch+bugs) → needinfo?(tschuster)
No longer regressions: 1805678
Regressions: 1805678

That's quite a sweeping claim; it would be useful if you clarified how "most" changes here make things worse.

Sorry. I only scrolled through https://hg.mozilla.org/mozilla-central/rev/a7850a6c640bbea189afdf53df02e87f05704548 which seems to show a lot of places where we are replacing __proto__ inside an object literal with a call to Object.setPrototyeOf. I see now that some of the later patches improve the current situation by using class .. extends.

It wasn't obvious, no. Peter did remind me once I had finished writing all the patches you see on this bug and put them up. We had a brief discussion about what to do, in which my impression was that there was no strong reason to prefer proto inside the literal over setPrototypeOf. ...

Other people might disagree, but I strongly prefer class > __proto__ inside object literal > Object.setPrototypeOf > proto (don't use this obviously). Using class instead of proto would be very nice, but I also see how updating some of this existing code would be tedious.

I can see how removing all instances of __proto__ would make it a lot easier to to audit everything. I just hope we don't end up with a situation where we remove proto but instead have Object.setPrototypeOf everywhere. Have we considered using a linter instead that allows it inside an object literal?

If it's really the case that using proto in an object literal is objectively better, then we can try reverting some of the patches here in a separate bug, but then we should probably also revisit that documentation...

Yeah I think it's not obvious to most people how proto inside an object literal is fundamentally different from calling the setter/getter. I think warning people away from it and to Object.setPrototypeOf is probably a mistake for that specific case. We should naturally always recommend to use class instead. Maybe other people also just have a different mental model.

Flags: needinfo?(tschuster) → needinfo?(jdemooij)

I don't have strong opinions on this. I agree with Tom that __proto__ in object literals is fine and a bit more concise (this also came up when we discussed this originally after Pwn2Own). Using Object.setPrototypeOf should be fine though, and might be a bit more explicit. Proto mutation no longer has the old performance cliffs fortunately.

Flags: needinfo?(jdemooij)
Flags: qe-verify-
Whiteboard: [post-critsmash-triage]
Whiteboard: [post-critsmash-triage] → [post-critsmash-triage][adv-main110-]
Group: core-security-release
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: