Bug 8241 - Named properties on window
Summary: Named properties on window
Status: RESOLVED FIXED
Alias: None
Product: WebAppsWG
Classification: Unclassified
Component: WebIDL (show other bugs)
Version: unspecified
Hardware: PC Linux
: P3 normal
Target Milestone: ---
Assignee: Cameron McCormack
QA Contact: public-webapps-bugzilla
URL: http://www.whatwg.org/specs/web-apps/...
Whiteboard:
Keywords: NE
Depends on:
Blocks: 13093
  Show dependency treegraph
 
Reported: 2009-11-08 21:19 UTC by Giovanni Campagna
Modified: 2011-09-24 12:05 UTC (History)
16 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Giovanni Campagna 2009-11-08 21:19:51 UTC
Window defines only a getter. According to latest WebIDL draft, this means that named properties are ReadOnly, which causes to ignore all attempts to set them.
This is different to the browsers I tested (Firefox 3.5, Arora 0.10, Opera 10.0), which replace the corresponding named property with a new one, containing the new value.

Testcase:
<iframe src="http://example.org" name="iframe"></iframe>
<script>alert(iframe); iframe = "test"; alert(iframe);</script>

Note: this may be a bug in WebIDL instead.
Comment 1 Michael[tm] Smith 2009-11-11 11:32:34 UTC
http://www.whatwg.org/specs/web-apps/current-work/multipage/browsers.html#dom-window-nameditem
> Window defines only a getter. According to latest WebIDL draft, this means that
> named properties are ReadOnly, which causes to ignore all attempts to set them.
> This is different to the browsers I tested (Firefox 3.5, Arora 0.10, Opera
> 10.0), which replace the corresponding named property with a new one,
> containing the new value.
> 
> Testcase:
> <iframe src="http://example.org" name="iframe"></iframe>
> <script>alert(iframe); iframe = "test"; alert(iframe);</script>
> 
> Note: this may be a bug in WebIDL instead.
> 

Comment 2 Ian 'Hixie' Hickson 2010-01-06 08:15:35 UTC
EDITOR'S RESPONSE: This is an Editor's Response to your comment. If you are satisfied with this response, please change the state of this bug to CLOSED. If you have additional information and would like the editor to reconsider, please reopen this bug. If you would like to escalate the issue to the full HTML Working Group, please add the TrackerRequest keyword to this bug, and suggest title and text for the tracker issue; or you may create a tracker issue yourself, if you are able to do so. For more details, see this document:
   http://dev.w3.org/html5/decision-policy/decision-policy.html

Status: Partially Accepted
Change Description: see diff given below
Rationale: I've added "ReplaceableNamedProperties" to Window, but that needs to be defined in WebIDL for this to make sense.
Comment 3 Ian 'Hixie' Hickson 2010-01-17 07:39:03 UTC
Oops, I screwed up adding the diff link. My bad. Anyway the change is pretty simply IIRC, I just added [ReplaceableNamedProperties] to Window.
Comment 4 Ian 'Hixie' Hickson 2010-01-29 23:12:52 UTC
Reopening to assign to heycam.
Comment 5 Cameron McCormack 2011-03-14 04:09:04 UTC
Ian, are you looking for any particular behaviour here?  [Replaceable] on IDL attributes means that the accessor property has a setter that will define a new data property on the object, which shadows the accessor property (since it lives on the prototype).

From http://people.mozilla.org/~cmccormack/tests/window-named-properties.html I get these results, for testing what happens when you declare a variable with the same name as a named property (named "abc"):

Firefox:
* "abc" is an own property on window; it is a data property, writable = true, enumerable = false, configurable = true, value = [object Window]
* after the "var abc", the own property remains a data property, writable = true, enumerable = false, configurable = true, and its values changes to 123

Safari:
* "abc" is an own property on window; it is a data property, writable = false, enumerable = false, configurable = false, value = [object DOMWindow]
* after the "var abc", it claims to be remain a data property, writable = false, enumerable = false, configurable = false, value = [object DOMWindow] (so the [[Get]] must be doing (permissible) some host object lying)

Chrome:
* it claims that "abc" is an own property on window's prototype, but getOwnPropertyDescriptor returns null (which is a lie which is not allowed by the spec, I think)
* after the "var abc", window.abc is an own data property, writable = true, enumerable = true, configurable = false, value = 123

IE:
* "abc" is an own property on window; it is a data property, writable = true, enumerable = true, configurable = true, value = [object Window]
* after the "var abc", window.abc remains an own data property, writable = true, enumerable = true, but configurable = false, value = 123

According to Web IDL, named properties should be accessor properties anyway, which none of the above do.  I propose that [ReplaceableNamedProperties] does the following to named properties for which there is a name getter but no name setter:

* keeps named properties as being own accessor properties on the object
* keeps them enumerable
* makes them configurable regardless of whether there is a "name deleter"
* gives them a setter, which will call [[DefineOwnProperty]] on the object to convert itself to a configurable, enumerable data property

The reason I would say to make the reconfigured data property configurable is that it's not possible within the bounds of ES5 to tell the difference between the property being assigned to and a var declaration causing [[Put]] to be called on the global (via SetMutableBinding).

[ReplaceableNamedProperties] would be disallowed when there is a name setter.
Comment 6 Ian 'Hixie' Hickson 2011-05-27 00:25:49 UTC
iirc we recently figured out there was some hack we could do with the prototype chain to do this instead of using the extended attribute given above. Anyone remember where we discussed that?
Comment 7 Cameron McCormack 2011-06-19 03:06:58 UTC
Now that we are going back to defining named property behaviour in terms of ECMAScript internal methods ([[DefineOwnProperty]], [[GetOwnProperty]], etc.) we can use them to implement [ReplaceableNamedProperties] rather than something in the prototype.  I've done that:

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.xml.diff?r1=1.303;r2=1.304;f=h
Comment 8 Boris Zbarsky 2011-06-19 14:22:37 UTC
I'd like some public-script-coord input on comment 7's solution.  In particular on how it interacts with var and the like....

In general, I would prefer things that require fewer deviations from default ES behavior here if there is a choice, just in terms of implementation difficulty.
Comment 9 Cameron McCormack 2011-06-19 22:41:54 UTC
I assumed since there was no [OverrideBuiltins] on the interface that that's how it behaved everywhere.  Stupid of me to assume. :)

Here's a small test (not to do with var, just with visibility of the named properties):

http://people.mozilla.org/~cmccormack/tests/window-named-override.html

* Firefox shows window objects for toString, open, alert & history, and
  do the normal property lookup for document and the variable.  (This might be
  because `window.hasOwnProperty("document") == true` in Firefox.)

* Safari/Chrome show window objects for toString, open & alert, and do
  normal property lookup for document, history and the variable.  (This might
  be because IDL attributes are still own properties on the object in these
  implementations.)

* Opera shows a window object for toString, document & history, and does
  normal property lookup for open, alert and the variable.  (So maybe Opera
  is not letting named properties override functions from Window, but
  otherwise is [OverrideBuiltins].)

* IE does normal property lookup for all of them.

I guess Firefox/Safari/Chrome behaviour can be summarised as "resolve own properties first, then named properties, then properties from the prototype".

IE's behaviour matches the spec for a non-[OverrideBuiltins] interface -- any properties that exist on the object itself or prototype get resolved in preference to the named properties.  This is also the most consistent of the lot.  Would pages with non-IE code paths break if all the other browsers switched to this?

All of this might be more a question for the already-resolved bug 10340, but it does impact on how we might require [ReplaceableNamedProperties] to be implemented.


We already require funny [DefineOwnProperty] etc. behaviour to handle named properties, so I don't think it's too much of a stretch to extend them to handle [ReplaceableNamedProperties].  The alternative which I guess is what Boris is alluding to is to have named properties appear to be on an object somewhere in the prototype chain instead, so that assigning to them or doing a variable declaration gets the right behaviour without adding more specialness into [DefineOwnProperty].

If we work under the assumption that Window is indeed non-[OverrideBuiltins], like IE, then that extra object in the prototype chain still needs to have special [GetOwnProperty] behaviour so that it first resolves properties from its own properties or its prototype chain before returning the named properties.

If we did something Safari/Chrome-like, where you resolve own properties, then named properties, then prototype properties, then you could stick an extra object in the prototype chain above the Window object which behaved like [OverrideBuiltins].  Again, this would avoid making the changes to [[DefineOwnProperty]] I made in comment 7.
Comment 10 Cameron McCormack 2011-06-20 00:56:52 UTC
I was fooled earlier by the Web Console in Firefox -- it doesn't actually have document as an own property on window.  (That's just in the Web Console's global object. :/)  So why document is given special treatment is not apparent to me.


Here are some tests wrt var versus assignment.

http://people.mozilla.org/~cmccormack/tests/window-named-var-before.html
http://people.mozilla.org/~cmccormack/tests/window-named-var-after.html
http://people.mozilla.org/~cmccormack/tests/window-named-assign-before.html
http://people.mozilla.org/~cmccormack/tests/window-named-assign-after.html

These test show using var to declare, or just assigning to, variables names toString, open, alert, document, history and variableName, either before or after those names become named properties (i.e. before or after <iframe>s with those names are in the document).  They show the values and whether the properties are configurable/enumerable/writable (except for Opera, where we don't have Object.getOwnPropertyDescriptor yet).

So according to ES5, using var to declare a variable P at the top level should do this:

  * If [[HasProperty]](P) returns false:
      * Call [[DefineOwnProperty]]
          (P, {value:undefined, writable:true,
               enumerable:true, configurable:false}, true).
      * Call [[Put]](P, undefined, isStrictMode).

Variable assignment is this, in non-strict mode:

  * Call [[Put]](P, value, false).

Since Window is an object with named properties, according to Web IDL at the moment we silently treat all non-configurable property definitions and configurable.  (That's a recent change, so nobody does that yet.  That might also change a bit if proxies gain the ability to expose non-configurable properties.)  So per spec there should be no difference between var declaration and plain assignment with window as the global object.

All of the variable names we're testing with the exception of variableName should already exist as properties from the Window object's prototype chain (but not be own properties).

So for window-named-var-before and window-named-assign-before, what we would expect from the specs as they stand is to have configurable/writable/enumerable own properties on the Window object before the iframes are added, with their values as specified.  After the iframes are added, looking up properties on window should be no different.

This is how implementations currently differ from this:
  * Everyone creates non-configurable properties for the var declarations.
  * WebKit makes the var declared properties appear to be non-writable and
    non-enumerable.  (Seems bogus.)
  * Firefox ignores the document variable declaration and assignment.
  * Safari/Chrome don't allow document to be declared as a variable, they
    throw an exception.  history can be, though.
  * Safari appears to override [[Get]] to return the named values, rather than
    [[GetOwnProperty]] -- so you can see that `window.toString == 1` but 
    `Object.getOwnPropertyDescriptor(window, "toString").value == aWindowObj`.
  * (Chrome and Safari both have some weirdness where the value of
    window.document is the same both before and after the
    <iframe name=document> is added, but afterwards the object cannot be
    stringified.)
  * IE doesn't let document or history variables be declared at all, it throws
    an exception.  So document and history named properties show through.
  * In window-named-assign-before, Firefox ignores the attempt to assign
    to history without a variable declaration, thus the named property shows
    through after the <iframe name=history> is added.

window-named-var-after and window-named-assign-after should per current specs also behave the same as each other.  Each of the properties should already exist on window: [[HasProperty]] will return true, so variable declarations are the same as plain assignment.

  * In Firefox/Safari/Chrome, any difference between running -var-after and
    -assign-after is just in the configurability of some properties (if any).
  * Firefox still exposes document as an HTMLDocument object, so assigning to
    it has failed again.  The other properties are exposed with their new
    values.
  * Chrome behaves the same as Firefox.
  * WebKit exposes DOMWindow objects for all properties except document and
    history, just as with the -var-before/-assign-before tests.
  * IE exposes the new property values for toString, open, alert and
    variableName and the document/history objects for document and history
    in -var-after.  -assign-after is the same except that toString is exposed
    as the toString function!  Not sure why assigning to toString without a
    variable declaration should fail.

I didn't test yet what would happen if Object.defineProperty were used for each of these property names on window.

So what is the upshot of all of this?  I'm guessing that it's important for compatibility for document to be exposed as the HTMLDocument object always.  Apart from that, there's a fair degree of variability.
Comment 11 Boris Zbarsky 2011-06-20 03:21:20 UTC
In the Firefox, case at least, I think part of your problem is that you're lumping together _different_ sorts of named properties.  In particular frame names are treated quite differently from properties that come from the global scope polluter in Gecko; I can't speak to other browsers.

The exact Gecko name resolution process on Window is:

1)  Something with standard classes (Object, Array, etc).  Not quite sure what
    and how those interact with named frames and the like.
2)  Look for a named frame with that name.
3)  Resolve "_content", "location", "navigator", "document".  Of those,
    "location" and "navigator" are non-configurable, so if you look them up
    before frames with those names are added, you won't be able to override
    them... or something.  I see no particular magic for "document" that would
    obviously explain your results.
4)  "java" and "packages"... I have no idea what that stuff is, except Java is
    involved.
5)  Event handlers.
6)  Properties off the prototype chain.
7)  Global scope polluter.
Comment 12 Brendan Eich 2011-06-20 05:18:52 UTC
(In reply to comment #11)
> In the Firefox, case at least, I think part of your problem is that you're
> lumping together _different_ sorts of named properties.  In particular frame
> names are treated quite differently from properties that come from the global
> scope polluter in Gecko; I can't speak to other browsers.
> 
> The exact Gecko name resolution process on Window is:
> 
> 1)  Something with standard classes (Object, Array, etc).  Not quite sure what
>     and how those interact with named frames and the like.
> 2)  Look for a named frame with that name.

This is a decision tree (skinny, one path only, so a list). Since (2) comes after (1) we can be sure that buitl-ins (standard classes such as Object) are resolved in preference to frames of the same name. Of course frame indexes cannot name any built-in in ECMA-262, so those are resolved in a step (0).

Also, there is a step (1.5) where 'constructor' is handled specially, so that a frame with that name cannot shadow the prototype property of that name on Window. I'm not sure this is anything but a historical accident, though.

Re: comment 10: it is important for integrity and optimizability that var-defined bindings be non-configurable.

/be
Comment 13 Cameron McCormack 2011-06-28 00:45:43 UTC
(In reply to comment #11)
> In the Firefox, case at least, I think part of your problem is that you're
> lumping together _different_ sorts of named properties.  In particular frame
> names are treated quite differently from properties that come from the global
> scope polluter in Gecko; I can't speak to other browsers.

Thanks, that's indeed what I've been missing.  I did some more testing:

http://people.mozilla.org/~cmccormack/tests/window-named-frame-vs-polluter.html
http://people.mozilla.org/~cmccormack/tests/window-named-frame-vs-polluter-quirks.html

> The exact Gecko name resolution process on Window is:

I got slightly different results for Gecko than your ordering -- in particular, it looks like global scope polluter properties do get resolved in preference to event handler properties.

So, ignoring the location/navigator/document/java/packages trickiness, the above tests tell me the following about what things frame properties and global scope pollution properties override:

  Firefox:
    * Frame properties override:
        Object.prototype properties, builtin and added
        Window.prototype properties, builtin and added
        event listener properties
      but not:
        JS builtin globals
        constructor
        variables or assignments on global
    * GSP properties override:
        event listener properties
      but nothing else.

  Chrome:
    * Frame properties override:
        Object.prototype properties, builtin and added
        Window.prototype properties, builtin and added
        event listener properties
        constructor
      but not:
        JS builtin globals
        variables or assignments on global
    * GSP properties override nothing.

  Safari:
    * Frame properties override:
        Object.prototype properties, builtin and added
        Window.prototype properties, builtin and added
      but not:
        JS builtin globals
        event listener properties
        constructor
        variables or assignments on global
    * GSP properties override nothing.

  Opera:
    * Frame properties override:
        Object.prototype properties, builtin and added
        Window.prototype properties, builtin and added
        event listener properties
        constructor
      but not:
        JS builtin globals
        variables or assignments on global
    * GSP properties override:
        Object.prototype properties, builtin and added
        Window.prototype added properties
        event listener properties
        constructor
      but not:
        Window.prototype builtin properties
        or anything else

  IE:
    * Frame properties override nothing.
    * GSP properties override:
        Window.prototype builtin properties
      but not:
        Window.prototype added properties
        or anything else.

Everyone is different, some slightly some wildly.  (And none of these schemes fits in with the model of having a single set of named properties on Window.)

For the global scope polluter properties, ignoring event listener properties for the moment, we have Firefox, Chrome and Safari all putting them at the bottom of the resolution chain.  IE does the same except that elements with IDs that match any of the Window.prototype builtin names (like open, alert, etc.), the GSP property wins.  Opera behaves quite differently; GSP properties override everything except for frame names, Window.prototype builtin names and own properties on the window object (variables, JS builtin constructors).

For frame properties, Firefox/Chrome/Safari/Opera all have them override properties from the prototype chain and not own properties on the window, but whether they override event listener properties or "constructor" is inconsistent.  (There'll definitely be differences in whether the event listener properties are own properties on the window vs accessor properties on Window.prototype.)  IE is the odd one out, where frame properties don't override anything except for GSP properties.  Did IE do this to match what the specs currently say?  I'm a little surprised that didn't break anything.

Here is a simple first order approximation to the different resolution orders (and this is most of a difference for IE):

  1. Own properties on window (which would include JS builtin
     global properties like Array, Object, etc.)
  2. Frames
  3. Properties from the prototype chain (which would include
     "constructor" & event listener properties)
  4. Global scope polluter

Would this work?
Comment 14 Boris Zbarsky 2011-06-28 02:48:39 UTC
> in particular, it looks like global scope polluter properties do get resolved
> in preference to event handler properties.

Hmm.  That's odd, and will probably change as we move event handler properties into IDL in Gecko.  In particular, right now they're own properties of the Window, but will move to the prototype when we do that.

> Would this work?

I believe it would work for me, but this may be worth bringing up on the mailing list; I can't even speak for Mozilla as a whole here...
Comment 15 Cameron McCormack 2011-06-30 02:39:41 UTC
I've made the proposed change, since it's certainly closer to where we need to be than where we are at the moment.  We can refine it if necessary.

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.xml.diff?r1=1.326;r2=1.327;f=h

The change here is to introduce a term "resolved before prototype properties".  The HTML5 spec would need to state which of Window's supported named properties are resolved before prototype prototypes.  And that would be the ones that don't correspond to the global scope polluter properties.  No changes to the extended attributes specified on Window are needed (just leave it as [ReplaceableNamedProperties]).
Comment 16 Tony Ross [MSFT] 2011-07-01 17:48:37 UTC
> IE is the odd one out, where frame properties don't
> override anything except for GSP properties.  Did IE do this to match what the
> specs currently say?  I'm a little surprised that didn't break anything.

Sorry for the delay in my response. I've been digging through our bug database to see if we had noticed any impact from this change. I didn't find anything.

>   IE:
>     * Frame properties override nothing.
>     * GSP properties override:
>         Window.prototype builtin properties
>       but not:
>         Window.prototype added properties
>         or anything else.

This is slightly incorrect. GSP properties do not override Window.prototype builtin properties in IE. I suspect you arrived at this conclusion because your test case attempts to override the "stop" builtin, but "stop" is not defined in IE. IE's actual behavior is:

  IE:
    * Frame properties override nothing (except GSP)
    * GSP properties override nothing

> Here is a simple first order approximation to the different resolution orders
> (and this is most of a difference for IE):
> 
>   1. Own properties on window (which would include JS builtin
>      global properties like Array, Object, etc.)
>   2. Frames
>   3. Properties from the prototype chain (which would include
>      "constructor" & event listener properties)
>   4. Global scope polluter
> 
> Would this work?

This is close to the behavior IE has today, except for resolving frames before the prototype chain. We have not seen resolving frames after the prototype chain break anything. Thus I prefer to avoid special-casing frames in this way and instead stick with IE's current behavior:

   1. Own properties on window (which would include JS builtin
      global properties like Array, Object, etc.)
   2. Properties from the prototype chain (which would include
      "constructor" & event listener properties)
   3. Frames
   4. Global scope polluter
Comment 17 Cameron McCormack 2011-07-03 21:45:47 UTC
(Adding some Opera/Chrome/WebKit people.)

(In reply to comment #16)
> Sorry for the delay in my response. I've been digging through our bug database
> to see if we had noticed any impact from this change. I didn't find anything.

OK.

> This is slightly incorrect. GSP properties do not override Window.prototype
> builtin properties in IE. I suspect you arrived at this conclusion because your
> test case attempts to override the "stop" builtin, but "stop" is not defined in
> IE. IE's actual behavior is:
> 
>   IE:
>     * Frame properties override nothing (except GSP)
>     * GSP properties override nothing

Ah, thanks for pointing this out.  That makes more sense.

> > Here is a simple first order approximation to the different resolution orders
> > (and this is most of a difference for IE):
> > 
> >   1. Own properties on window (which would include JS builtin
> >      global properties like Array, Object, etc.)
> >   2. Frames
> >   3. Properties from the prototype chain (which would include
> >      "constructor" & event listener properties)
> >   4. Global scope polluter
> > 
> > Would this work?
> 
> This is close to the behavior IE has today, except for resolving frames before
> the prototype chain. We have not seen resolving frames after the prototype
> chain break anything. Thus I prefer to avoid special-casing frames in this way
> and instead stick with IE's current behavior:
> 
>    1. Own properties on window (which would include JS builtin
>       global properties like Array, Object, etc.)
>    2. Properties from the prototype chain (which would include
>       "constructor" & event listener properties)
>    3. Frames
>    4. Global scope polluter

So that is definitely simpler and doesn't need the hook I added to Web IDL.  It means the interface can remain a non-[OverrideBuiltins] one.  (It also means no further spec change would be needed, except perhaps to remove the Web IDL hook which otherwise wouldn't be used.  Note that the HTML spec doesn't yet use the hook; that's bug 13093.)

Does anyone have an opinion on this simpler behaviour?
Comment 18 Cameron McCormack 2011-08-31 03:28:00 UTC
OK, I've made the not to split up named properties to before and after properties from the prototype.  HTML will need wording to ensure that frame properties are resolved before GSP properties.

http://dev.w3.org/cvsweb/2006/webapi/WebIDL/Overview.html.diff?r1=1.365;r2=1.366;f=h

Tony, can you indicate whether the change is acceptable, thanks.
Comment 19 Travis Leithead [MSFT] 2011-09-06 21:15:21 UTC
After re-checking the latest editor's draft, and talking with Tony, I confirm that what we have now is acceptable.

Thanks for driving this to resolution.

-Travis
Comment 20 Ian 'Hixie' Hickson 2011-09-23 23:50:18 UTC
heycam: Is there a bug on the changes I need to make to the HTML spec?
Comment 21 Ian 'Hixie' Hickson 2011-09-24 00:07:58 UTC
Nevermind, found bug 13093.