whatwg / webidl

Web IDL Standard
https://webidl.spec.whatwg.org/
Other
409 stars 164 forks source link

Named properties object / named property visibility algorithm with property on Window.prototype #607

Open Ms2ger opened 5 years ago

Ms2ger commented 5 years ago

When there's a property on Window.prototype, the named property visibility algorithm called on window will return false in step 5.1, when prototype is Window.prototype. This implies that [[GetOwnProperty]] on the named properties object will fall back to calling OrdinaryGetOwnProperty(O, P), which returns undefined.

However, the browsers I tested consistently return the result of the named getter.

Consider the following code:

<!DOCTYPE html>
<span id=foo></span>
...<script>
var wp = window.__proto__;
var npo = window.__proto__.__proto__;
wp.foo = 7;
w(wp)
w(npo)
w(window.foo)
w(wp.foo)
>>>> w(npo.foo);

w("------")

var ep = npo.__proto__;
ep.bar = 7;
w(ep)
w(window.bar)
w(wp.bar)
w(npo.bar);
w(ep.bar);
</script>

This logs the same in Firefox, Chrome dev and Epiphany:

log: object "[object WindowPrototype]" (4 props: foo=7, addEventListener=function addEventListener() {\n    [native code]\n}, removeEventListener=function removeEventListener() {\n    [native code]\n}, dispatchEvent=function dispatchEvent() {\n    [native code]\n})
log: object "[object WindowProperties]" (3 props: addEventListener=function addEventListener() {\n    [native code]\n}, removeEventListener=function removeEventListener() {\n    [native code]\n}, dispatchEvent=function dispatchEvent() {\n    [native code]\n})
log: 7
log: 7
>>>> log: object "[object HTMLSpanElement]" (242 props: click=function click() {\n    [native code]\n}, focus=function focus() {\n    [native code]\n}, blur=function blur() {\n    [native code]\n}, title=""...)
log: ------

(Edit: ignore the results below; Chrome is doing something weirder and I didn't notice because I failed to actually include the span.)

log: object "[object EventTargetPrototype]" (4 props: addEventListener=function addEventListener() {\n    [native code]\n}, removeEventListener=function removeEventListener() {\n    [native code]\n}, dispatchEvent=function dispatchEvent() {\n    [native code]\n}, bar=7)
log: 7
log: 7
log: 7
log: 7

annevk commented 5 years ago

Well yes, but the operations you're using here invoke [[Get]], no? And [[Get]] invokes OrdinaryGet which goes over a chain as browsers do.

domenic commented 5 years ago

Yeah, to invoke [[GetOwnProperty]] you'd need to use Object.getOwnPropertyDescriptor(window, "foo") or similar.

bzbarsky commented 5 years ago

Testcase that actually exercises [[GetOwnProperty]]: http://software.hixie.ch/utilities/js/live-dom-viewer/?saved=6506

Looks to me like Safari and Firefox are following the spec here. Chrome is not: it returns a property descriptor from npo for property name "bar" pointing to one of the <span>s, but somehow a [[Get]] on the window returns 7, skipping over that property that it claims exists. So the observable effect of [[Get]] on the window is the same, which is what largely matters for web compat, but Chrome is using some sort of weird magic to implement it.

bzbarsky commented 5 years ago

Ah, @Ms2ger clarified that he's talking about this case, specifically:

  1. There is an element with id "foo".
  2. There is a property on Window.prototype with name "foo".
  3. You do a property lookup for "foo", via [[Get]] or [[GetOwnProperty]] on the named properties object.

Per spec, those lookups should not find the element, because https://heycam.github.io/webidl/#named-properties-object-getownproperty step 2 does the visibility check on the window, not on the named properties object itself, finds the property on Window.prototype, and then says the named property object has no property named "foo".

As @Ms2ger points out, no browsers do that. What's really at stake here is making sure that the named properties object doesn't shadow anything higher on the prototype chain, so that's what Firefox checks: that there is no such property on the prototype chain of the named properties object. Window.prototype is not on said proto chain, but also can't be shadowed by the named properties object, so doesn't have to be checked.

I suspect we could take out step 2 there and remove the check for a "named properties object" in https://heycam.github.io/webidl/#dfn-named-property-visibility step 5.1 and things would be just fine web compat wise, and the behavior simpler/saner.

domenic commented 2 months ago

I can't tell if this is fixed.

The current spec seems to have been changed at least once since this issue was filed. But I still don't understand something about the current spec.

https://webidl.spec.whatwg.org/#named-properties-object-getownproperty step 4.1 guards [[GetOwnProperty]] with the named property visibility algorithm.

https://webidl.spec.whatwg.org/#dfn-named-property-visibility step 2 says

If O has an own property named P, then return false.

This implies to me that for a document like

<iframe id="DOMRect"></iframe>

the named properties object should not contain any value for DOMRect. But that is not the case in at least Chrome and Firefox: https://jsbin.com/nopokiqocu/1/edit?html,output