The global object in browsers

View: New views
7 Messages — Rating Filter:   Alert me  
< Prev | 1 - 2 - 3 | Next >

Re: The global object in browsers

by David-Sarah Hopwood :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Maciej Stachowiak wrote:

> On Feb 19, 2009, at 1:39 AM, David-Sarah Hopwood wrote:
>> Ian Hickson wrote:
>>> On Tue, 17 Feb 2009, Mark Miller wrote:
>>>> On Tue, Feb 17, 2009 at 5:03 PM, Ian Hickson <ian@...> wrote:
>>>>> Indeed, I noted this earlier. The behavior HTML5 codifies is the
>>>>> behavior that the majority of browser vendors have asked me to codify.
>>>> Majority, huh? Which vendors? How does the behavior they ask for
>>>> correlate with what their browsers do?
>>>
>>> Opera, Apple, and Mozilla. The HTML5 spec originally specced what IE
>>> does, namely throw an exception when running code whose global object doesn't
>>> match the current Window object, but Opera, Apple, and Mozilla rejected
>>> this on the grounds that it could not be implemented in a
>>> high-performance manner.
>>
>> That is clearly false. It would be a single pointer comparison when
>> entering a new context.
>>
>> I make no comment here on whether this behaviour would be a good idea on
>> other criteria, just that rejecting it on performance grounds is absurd.
>
> In modern JITing implementations, adding (at least) two memory reads and
> a conditional branch to every function call would be a significant
> performance hit.

It is not every function call; only function calls that are not known
to be same-context (in a particular copy of the generated code). The
majority (by call frequency) of function calls can be inferred to be
same-context by analyses that a high-performance implementation should
be doing already. Furthermore, the context check can be hoisted to the
first point in a function body where the target function is known (so
calls to the same function in a loop will require only one check).

There are most sophisticated optimizations that could be done, but
they're probably not needed.

> In JavaScriptCore for instance, the hot path at the
> machine code level is optimized down to essentially just one memory
> read, one conditional branch, and a jump to the callee's code (also some
> memory writes but those don't stall the pipeline so they don't matter as
> much). The next hottest path has three branches and a few extra memory
> reads. Adding an extra branch (and associated memory reads) to that
> would be a big hit. We know because we have measured the benefit of
> reducing the number of branches. It makes a huge difference in
> call-heavy code.
>
> In general, I would advise against making performance claims in absolute
> terms (like "clearly false") without testing or studying the relevant
> implementation internals.

I see no point in equivocating on points that I am quite sure about,
having studied similar issues in implementations of other languages.

--
David-Sarah Hopwood
_______________________________________________
Es-discuss mailing list
Es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by David-Sarah Hopwood :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Maciej Stachowiak wrote:

> On Feb 19, 2009, at 1:20 AM, David-Sarah Hopwood wrote:
>> Ian Hickson wrote:
>>> On Tue, 17 Feb 2009, Mark S. Miller wrote:
>>>> I don't understand. If the object you're calling Window is inaccessible
>>>> from ES code, and if the object you're calling WindowProxy forwards
>>>> everything to your Window, why not just relabel Window ->
>>>> InternalWindow, WindowProxy -> Window?
>>>
>>> I don't really mind what the objects are called, the point is just that
>>> the object at the top of the scope chain is not the same as the object
>>> returned by "this" (or "window" on the global object).
>>
>> MarkM's point is that *given that the object called Window is inaccessible*,
>> there's no way to observe that the object called Window is at the top of
>> the scope chain. An implementation could reflect all property changes
>> in that object to the object called WindowProxy, by some unspecified
>> mechanism (which is allowed since they are both host objects).
>
> It is possible to observe that the object at the top of the scope chain
> behaves differently than the global "this" value (it may have an
> entirely different set of properties), so this arguably violates the
> ECMAScript requirement that these be the same object, even though object
> identity cannot be observed directly.

Ian Hickson's description of the two objects was:

# The global object is a Window object. This object is per-Document.
# The object returned by the "window" attribute on that global object
# is actually a WindowProxy object, which forwards everything to the
# "current" Window object.

I don't understand how the WindowProxy "forwarding everything" to
the Window object is is consistent with the two objects having
"entirely different set[s] of properties".

In any case, note that host objects can have arbitrary [[Put]] and
[[Get]] internal methods, so it is possible for them to implement
almost any conceivable behaviour that HTML5 could specify (given
that ES code cannot obtain a reference to the object at the top of
the scope chain, and so === cannot be used on it). That was my point
above. In other words, ES3 has such a weak specification for host
objects that literally any behaviour for property accesses on them is
conformant.

[...]
>> I'm confused by the motivation of the change in HTML5. It seems like
>> it is imposing most of the complexity that would be needed to fix
>> some of the security problems associated with the global object,
>> *without* actually fixing those problems.
>
> The HTML5 spec behavior does fix important security problems, relative
> to what older browsers used to do. Older behavior was to reuse the same
> global object across navigations, but simply clear the variables. This
> creates easily exploitable XSS vulnerabilities.

That's obviously broken, yes. When you say "older behaviour", what versions
of the main browsers are you talking about, approximately?

> Note though that HTML5 is following the implementations here rather
> than leading.
>
>> Also, it is a breach of standards development etiquette for the HTML
>> WG to make a a change (even in a draft) that it believes to be
>> incompatible with the ECMAScript spec, without consulting TC39. It
>> should not have been left to you in the role of an implementor to
>> point out the incompatibility.
>
> I think Ian discharged his obligation by notifying TC39 of the issue and
> starting this discussion. At this point, the important thing is to come
> up with a solution we can agree on.

I was confused partly by the fact that Ian said:

# For HTML5, this behaviour has been defined in more detail. [...]
# The HTML5 spec says: [...]

as opposed to something like: "It has been proposed for the next draft
of HTML5 to define this in more detail. [...] The proposal is: [...]"

--
David-Sarah Hopwood

_______________________________________________
Es-discuss mailing list
Es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by David-Sarah Hopwood :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Ian Hickson wrote:

> Right now ES3 assumes that there is a single global object, which is used
> at the top of the scope chain and that is returned for "this" in the
> global scope.
>
> It is possible to show that this is now what some browsers do:
>
>    var x = 1;
>    function f() { return x; }
>    var global = this;
>    function g() { return global.x; }
>
>    // some other page's script takes references to f and g
>    // browser navigates to a new page
>
>    var x = 2;
>
> Now, if the other page's script calls f() and g(), it will get different
> results [...]

Suppose that a browser allocates all JavaScript objects associated with
some unit of content [*], in an arena. When the browser navigates away from
that unit of content, the arena is deallocated; to preserve memory safety,
all references into it from objects that are still live will throw an
exception.

This behaviour has clear advantages for robustness against denial of service
from JavaScript code, both deliberate and inadvertent -- which is a definite
weak spot of current browsers, and a very common cause of complaint from
knowledgeable users. Is there any reason why it should be considered
nonconformant?

[*] Possibly a frame, or consecutive sequence of navigated frames with
    the same origin. What is the minimum granularity for a "unit of content"
    for this would be compatible with the current web?

--
David-Sarah Hopwood ⚥



_______________________________________________
Es-discuss mailing list
Es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by Maciej Stachowiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Feb 21, 2009, at 1:49 AM, David-Sarah Hopwood wrote:

> Ian Hickson wrote:
>> Right now ES3 assumes that there is a single global object, which  
>> is used
>> at the top of the scope chain and that is returned for "this" in the
>> global scope.
>>
>> It is possible to show that this is now what some browsers do:
>>
>>   var x = 1;
>>   function f() { return x; }
>>   var global = this;
>>   function g() { return global.x; }
>>
>>   // some other page's script takes references to f and g
>>   // browser navigates to a new page
>>
>>   var x = 2;
>>
>> Now, if the other page's script calls f() and g(), it will get  
>> different
>> results [...]
>
> Suppose that a browser allocates all JavaScript objects associated  
> with
> some unit of content [*], in an arena. When the browser navigates  
> away from
> that unit of content, the arena is deallocated; to preserve memory  
> safety,
> all references into it from objects that are still live will throw an
> exception.
>
> This behaviour has clear advantages for robustness against denial of  
> service
> from JavaScript code, both deliberate and inadvertent -- which is a  
> definite
> weak spot of current browsers, and a very common cause of complaint  
> from
> knowledgeable users. Is there any reason why it should be considered
> nonconformant?

This behavior has two problems:

1) Likely incompatible with the Web. Though Web sites apparently don't  
depend on ability to call older functions, they certainly do use  
objects originally allocated in other global objects and quite likely  
after the originating context has navigated. It's hard to quantify  
this since no browser has ever tried.

2) Makes implementation of back/forward caching (as present in Safari  
and Firefox) impractical; b/f cache fully restores a context that you  
navigated away from, including the live JavaScript object graph.

3) Has the same performance problems as the model of checking at  
function call boundaries, since at calls you'd have to check if your  
function has turned into a magical exception object. You are on record  
as not believing these, I will leave it to others to judge for  
themselves whether your "I'm quite sure" argument outweighs the  
experience of those who actually tried it and measured the results.

4) If the arena is truly deallocated rather than filled with magic  
exception objects, many additional checks must be inserted each time a  
value reference is used in almost any way, to check whether it is a  
reference into a deallocated arena. This would likely be a significant  
perf hit as well.

5) As far as I can tell, this violates the ECMA spec even more than  
the current HTML5 solution; the ECMA spec does not include the concept  
of reachable values turning into exception-throwing zombies.

6) It has poor properties for reliability and integrity of ECMAScript  
programs. Your code may have a perfectly good string or object stored  
away. But depending on where it originally came from, that reference  
can suddenly go bad.

> [*] Possibly a frame, or consecutive sequence of navigated frames with
>    the same origin. What is the minimum granularity for a "unit of  
> content"
>    for this would be compatible with the current web?

A unit of content of one page is almost certainly incompatible with  
the Web. A series of frames with the same origin would likely also be  
incompatible, since it is quite likely an initially empty frame may be  
used as a helper before navigating elsewhere. Not only that, but it  
would be bizarrely arbitrary if your object references from another  
frame go dead or not depending on whether the frame navigates to same-
origin or non-same-origin content. Either way, problems 2-5 remain.

I don't think we need to try to redesign how browsers do navigation  
here. I don't see any justification provided for preferring your  
approach to what HTML5 specifies.

Regards,
Maciej

_______________________________________________
Es-discuss mailing list
Es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by Maciej Stachowiak :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message


On Feb 20, 2009, at 4:13 PM, David-Sarah Hopwood wrote:

> Ian Hickson's description of the two objects was:
>
> # The global object is a Window object. This object is per-Document.
> # The object returned by the "window" attribute on that global object
> # is actually a WindowProxy object, which forwards everything to the
> # "current" Window object.
>
> I don't understand how the WindowProxy "forwarding everything" to
> the Window object is is consistent with the two objects having
> "entirely different set[s] of properties".

Let's say you have a top-level browsing context currently displaying a  
document loaded from <http://example.com/>. This document has a  
subframe displaying <http://example.com/frame1.html>. Inside the  
frame1 browsing context, a variable X containing the value "frame1" is  
defined. A function F is also defined which accesses variable X via  
scope, and via a retained reference to the global object. The top-
level context gets a reference to function F. Now the nested browsing  
context is navigated to <http://example.com/frame2.html>. This  
establishes a new Window, which the WindowProxy now points to. Let's  
say that inside this new global object, another variable X is defined  
which has the value "frame2". Now when F is called from the outer  
context, it will consistently see the value "frame1" when looking up  
variable X via scope, since the scope chain contains its Window. But  
when accessing X via a saved reference to the global object (for  
example via window.X) it will consistently see "frame2", since this is  
a WindowProxy reference that forwards to the now-current Window.  
Taking this further, the old Window and new Window (visible via the  
WindowProxy) could have totally different sets of properties.

Note that to observe the difference requires at least two frames, at  
least one of which is navigated, for a total of 3 different global  
objects.

Does that help?

> In any case, note that host objects can have arbitrary [[Put]] and
> [[Get]] internal methods, so it is possible for them to implement
> almost any conceivable behaviour that HTML5 could specify (given
> that ES code cannot obtain a reference to the object at the top of
> the scope chain, and so === cannot be used on it). That was my point
> above. In other words, ES3 has such a weak specification for host
> objects that literally any behaviour for property accesses on them is
> conformant.

If we take this approach, then the requirement that the top level  
scope entry and the global object are the same object would be  
meaningless.  I'm willing to buy the argument that it is in fact  
meaningless and imposes no real requirement, but perhaps others will  
disagree. Since there is no way to observe identity directly, one  
could always make the claim that two different objects are in fact one  
object with strange property access behavior.


Regards,
Maciej


_______________________________________________
Es-discuss mailing list
Es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by Brendan Eich-3 :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

Picking up this older thread, I owed you and others in TC39 a reply  
from two face-to-face meetings ago.

On Feb 18, 2009, at 3:57 AM, Brendan Eich wrote:

> On Feb 17, 2009, at 11:18 PM, Mark Miller wrote:
>
>> You misunderstood me a bit, but no matter.
>
> Sorry, I couldn't see how to interpret your proposal otherwise. Let  
> me know what I missed if you like.
>
> Maciej's right, the object identities practically dictate split  
> windows. I suppose the original DOM level 0 could have made the  
> split explicit, but it was not implemented this way at all back in  
> the day. Different browser implementors solved the security and  
> performance problems in similar ways, to preserve the view of the  
> persistent window container as the one true "window object", really  
> a proxy with multiple global objects hidden within it.

The issue we were debating in the TC39 meeting in March at Yahoo! was  
whether |this|, window, self, and any other synonyms should bind to  
the inner or outer window object.

Recall that split windows arise because the outer window is the  
persistent object reference returned by window.open, frames[n],  
document.getElementById(frameId), etc. that perdures across document  
loads into that window or frame. The inner window is the ECMA-262  
global object, a capability through which unmediated access to  
sensitive variables including much of the DOM happens.

The inner window is thus the final object on the scope chain of all  
objects created for a particular page, whether induced by markup or  
created by DOM API calls. The outer window is a proxy that monitors  
accesses and forwards them to the current inner window, or denies them.

During the evolution of split windows in Mozilla's codebase, we  
observed that it's frightfully easy to leak the inner-window  
capability if it is allowed to escape to script. So we made |this|,  
window, and self bind to the outer window.

We even made our __parent__ extension, the read-only and undeletable  
property reifying the intrinsic scope chain link in SpiderMonkey,  
return the outer window, not the inner window that is the last object  
on the scope chain of objects subordinate to that inner window, e.g.,  
the current document, where document.__parent__ would seemingly  
reference the inner window containing document.

Instead, we "outerize" inner window references as they try to escape  
to user-level JS. Only privileged API can get the capability, and of  
course it's baked in as the lexical scope chain link by the JS  
compiler for top-level functions and variously optimized closures.

If the outer window sees that the "outerized" access is from the same  
origin as the *current* inner window, it allows access. This is  
expensive, or at least it has been until recently. With tracing and  
polymorphic inline caching and the like, it's no longer too expensive  
to consider imposing on all accesses.

(Maciej and I debated this with David-Sarah Hopwood for function  
calls, and the jury's still out; more on this later, but see the paper  
cited below for some encouraging results. But this is only one of the  
reasons for split windows, so even if we did check access always, we  
wouldn't give up split windows.)

The DOM does not use a capability model, rather it monitors certain  
references to implement access control policies, again because  
monitoring all references is too costly (or was in the nineties); also  
access control was still the rage back when JS and Java were co-
evolving their security models. These access control judgments depend  
on the baked-in and unforgeable intrinsic scope chain link, in order  
to find the principals for subject script and target object. But the  
DOM checks only some accesses, not all -- and in particular not access  
to JS variables.

Here's the paper I mentioned at the last face-to-face but forgot to  
follow up on (perhaps you've seen it already): http://www.adambarth.com/papers/2009/barth-weinberger-song.pdf 
  -- a nice paper on the problem of mixing capability with access-
control models -- old news to you I'm sure in its general results, but  
perhaps novel in the split window and DOM vs. JS browser conflict.

Section 4.2 in the paper talks about a split window bug, or possibly  
the lack of split windows altogether -- I *think*; I haven't looked  
closely at the WebKit code in question. 4.3 describes a bug that is  
very familiar to Mozilla JS hackers; nothing against WebKit here,  
we're all in the same boat.

The paper's conclusion that defense in depth requires universal access  
control checks at the JS level may not sit well with obj-cap fans, but  
it fits the threat-space we've been facing all these years. Blame the  
DOM, try to reform it or rewrite it (Caja, ADSafe) to use capabilities  
instead of ids and names and too many references, but in the short run  
the right fix for browser vendors dealing with the web-as-it-is looks  
to me like this:

Convolve security labels with polymorphic inline cache keys ("shapes")  
to fast-path same-origin accesses, and check all others for complete  
mediation. This work is happening in SpiderMonkey now. It will not  
relieve us of compatibility requirements for split windows, but it  
might allow us to bind |this| to the inner window. That doesn't say we  
*should * so bind in the HTML 5 spec, of course.

IIRC from the March meeting, you and Waldemar were in favor of binding  
|this| etc. to the inner window. I believe if we had done that in  
Mozilla starting with Firefox 1.5 (when split windows were finally  
implemented) we would have had significantly more exploits than we  
have had given the "outerizing" defense we chose.

Of course you shouldn't be able to tell whether |this| binds to inner  
or outer window, except when attacking a browser that access-checks  
only via the outer window. One that checks all accesses would stop all  
attacks, even when the inner-window capability leaked.

If we must have split windows in all top browser implementations (so  
the argument goes), then we must have them in a spec. If not ECMA-262,  
then HTML5. If split windows, then what |this| binds to (outer or  
inner) needs to be spec'ed. So here we are. Comments?

/be

> The ability to "use lexical scope" (however the syntax turns out)  
> and make the global variables truly lexical bindings in a top-level  
> environment, not properties of some grotty object, is something I  
> look forward to in Harmony:
>
> http://wiki.ecmascript.org/doku.php?id=strawman:lexical_scope
>
> /be
>
> _______________________________________________
> Es-discuss mailing list
> Es-discuss@...
> https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss

Re: The global object in browsers

by Ian Hickson :: Rate this Message:

Reply to Author | View Threaded | Show Only this Message

On Mon, 6 Jul 2009, Brendan Eich wrote:
>
> If we must have split windows in all top browser implementations (so the
> argument goes), then we must have them in a spec. If not ECMA-262, then
> HTML5. If split windows, then what |this| binds to (outer or inner)
> needs to be spec'ed. So here we are. Comments?

Your e-mail is in line with my understanding.

In HTML5, the "inner window" is the Window object and the "outer window"
is the WindowProxy object. With one minor exception to do with
about:blank, there's a 1:1 mapping from Document to Window, and a 1:1
mapping from WindowProxy to browsing context. Each browsing context can
have many Window/Document pairs.

For what it's worth, right now HTML5 says:

   If the script's global object is a Window object, then in JavaScript,
   the |this| keyword in the global scope must return the Window object's
   WindowProxy object.

   This is a willful violation of the JavaScript specification current at
   the time of writing (ECMAScript edition 3). The JavaScript
   specification requires that the this keyword in the global scope return
   the global object, but this is not compatible with the security design
   prevalent in implementations as specified herein. [ECMA262]

I'd love to be able to include this requirement without it being a
violation of another spec.

HTH,
--
Ian Hickson               U+1047E                )\._.,--....,'``.    fL
http://ln.hixie.ch/       U+263A                /,   _.. \   _\  ;`._ ,.
Things that are impossible just take longer.   `._.-(,_..'--(,_..'`-.;.'
_______________________________________________
es-discuss mailing list
es-discuss@...
https://mail.mozilla.org/listinfo/es-discuss
< Prev | 1 - 2 - 3 | Next >