Foreshadowing property cache bug possible when using one script in several globals

NEW
Unassigned

Status

()

8 years ago
11 months ago

People

(Reporter: jimb, Unassigned)

Tracking

Firefox Tracking Flags

(Not tracked)

Details

(Reporter)

Description

8 years ago
I think the property cache is unsound when we use a single script against different globals. (I hear we do this in XBL.) It's a so-called "foreshadowing" bug.

1) Create global objects g1 and g2 as follows:

   p = { a:1 }
   function G() { }
   G.prototype = p
   g1 = new G()
   g2 = new G()

2) Compile the following code, producing the JSScript S:

   function f(s) { eval(s); return function() { return a; } }
   f('')

3) Evaluate the script in the global g1, yielding c1, and then in g2, yielding c2.

4) Evaluate:

   g1.a = 2

This will cause a purge and reshape p.

4) Evaluate:

   c2()

This creates a property cache entry using f's call object's shape and p's new shape as the key and value shapes.

5) Evaluate:

   c1()

This will find the property cache entry created in step 4, skipping the binding for 'a' on g1.

The soundness of the property cache on long prototype chain searches (i.e. more than two objects) depends on the fact that objects with different prototypes have different shapes. But we need this guarantee for any kind of "long" search; it applies equally to scope chains.

Since the shape of the call object c1 and c2 close over doesn't depend on the identity of the global it takes as its parent, we have introduced the same sort of unsoundness that we would have with prototype chain searches if an object's shape did not depend on its prototype.
Hmm.  XBL only uses cloned function objects, and we should be able to give function clones with different parents different shapes (if we don't already).

XUL, on the other hand, does use entire JSScripts that it evaluates against different globals.  :(
Ick. Good find.

We had the "foreshadowing" bug where two same-shaped objects could have different prototype chains.

Then we had the "foreshadowing" bug where two same-shaped objects could have different scope chains.

This is the "foreshadowing" bug involving both the scope chain and the prototype chain.
(Reporter)

Comment 3

8 years ago
One fix for this might be to not cache searches that proceed into the prototype chain of the first non-CacheableNonGlobalScope at the end of the scope chain. That is, we'd cache up to the scope-to-prototype "elbow", but not beyond.
We don't have shared prototypes among multiple global objects in Chrome (XUL or XBL). That's a bad thing in general, although some embeddings may do it, or may have done it in the past, with "sealed" (now frozen) "superglobal" shared protos.

/be
(Reporter)

Comment 5

8 years ago
(In reply to comment #4)
> We don't have shared prototypes among multiple global objects in Chrome (XUL or
> XBL). That's a bad thing in general, although some embeddings may do it, or may
> have done it in the past, with "sealed" (now frozen) "superglobal" shared
> protos.

That's interesting --- so in Firefox's embedding, at least, this may not be an issue.

bz, can you confirm my understanding here? Given the explanation in comment 0, does the fact that different globals and their prototype chains have disjoint sets of shapes in Firefox get us off the hook there?

This would still be a bug for other embeddings, but just not a FF bug.
Hmm.

So to get this bug to happen we must have:

1)  Two functions that point to the same JSFunction.
2)  Two things that are on the scope chains when those functions are invoked and
    share a prototype.

Is that really all there is to it?  That is, what does happen in the function-clones-with-different-parents case in terms of call object shape?
(In reply to comment #6)
> 1)  Two functions that point to the same JSFunction.
> 2)  Two things that are on the scope chains when those functions are invoked
> and
>     share a prototype.

The functions sharing a prototype does not matter. The Call objects have shapes that depend on the function and (with the patch for bug 554955, if needed due to the parent scope being potentially extended to have new bindings) on the different object identities of the parent scopes.

> Is that really all there is to it?

This bug is not bug 554955 -- with that bug fixed, this one arises only if two or more global objects have a shared prototype.

> That is, what does happen in the
> function-clones-with-different-parents case in terms of call object shape?

See bug 554955.

/be
> The functions sharing a prototype does not matter.

Sure; I said the "things that are on the scope chains" share a prototype.

> with that bug fixed, this one arises only if two or more global objects have a
> shared prototype.

What's special about global objects here?  That is, why does the patch in bug 554955 fix all cases when the scope chain starts with a non-global object but not the case where it starts with a global?
Oh, this part:

 The shape of a CacheableNonGlobalScope covers the shapes of all its parents up
 to, but not including, the global object.

Why do we not want to include the global object in that shape?  Too much shape-changing going on with global objects?
(In reply to comment #8)
> > The functions sharing a prototype does not matter.
> 
> Sure; I said the "things that are on the scope chains" share a prototype.

Right, I was just trying to dispell potential confusion on anyone's part (mine at least).

> > with that bug fixed, this one arises only if two or more global objects have a
> > shared prototype.
> 
> What's special about global objects here?  That is, why does the patch in bug
> 554955 fix all cases when the scope chain starts with a non-global object but
> not the case where it starts with a global?

That is a good question!

/be
(Assignee)

Updated

4 years ago
Assignee: general → nobody
You need to log in before you can comment on or make changes to this bug.