Bug 786801 - js_InferFlags should not stop at compartment boundaries (r=bhackett)
☠☠ backed out by 04b67eeb817f ☠ ☠
authorLuke Wagner <luke@mozilla.com>
Tue, 04 Sep 2012 14:31:04 -0700
changeset 104232 7887ace84c7d0d3ae9df69bbb48b1c22bbcd9680
parent 104231 82f73bdb22379a198d1522881f2361210fb70ba7
child 104233 1661cbbc37595dfd319cc969f05e93d33fa98191
push id14413
push userlwagner@mozilla.com
push dateTue, 04 Sep 2012 23:51:43 +0000
treeherdermozilla-inbound@7887ace84c7d [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbhackett
bugs786801
milestone18.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 786801 - js_InferFlags should not stop at compartment boundaries (r=bhackett)
content/html/document/test/test_documentAll.html
js/src/jsobj.cpp
--- a/content/html/document/test/test_documentAll.html
+++ b/content/html/document/test/test_documentAll.html
@@ -17,16 +17,18 @@ Tests for document.all
 <div id="content" style="display: none">
   <a id="id1">A</a>
   <a id="id2">B</a>
   <a id="id2">C</a>
   <a id="id3">D</a>
   <a id="id3">E</a>
   <a id="id3">F</a>
 </div>
+<iframe id="subframe" src="data:text/html,<span id='x'></span>"
+        style="display: none"></iframe>
 <pre id="test">
 <script class="testbody" type="text/javascript">
 
 p = document.getElementById("content");
 
 // Test that several elements with the same id or name behave correctly
 function testNumSame() {
   is(document.all.id0, null, "no ids");
@@ -133,16 +135,24 @@ elementNames.forEach(function (name) {
     hasName.shift();
   }
   else {
     is(document.all[nameval], null, "shouldn't have name");
   }
 });
 is(hasName.length, 0, "found all names");
 
+SimpleTest.waitForExplicitFinish();
+addLoadEvent(function() {
+  var subdoc = $("subframe").contentDocument;
+  is(subdoc.all.x, subdoc.body.firstChild,
+     "document.all should work in a subdocument");
+  SimpleTest.finish();
+});
+
 // Utility functions
 function rC(node) {
   node.parentNode.removeChild(node);
 }
 function testArraysSame(a1, a2) {
   return Array.prototype.every.call(a1, function(e, index) {
     return a2[index] === e;
   }) && a1.length == a2.length;
--- a/js/src/jsobj.cpp
+++ b/js/src/jsobj.cpp
@@ -2396,26 +2396,23 @@ js_CreateThisForFunction(JSContext *cx, 
 }
 
 /*
  * Given pc pointing after a property accessing bytecode, return true if the
  * access is "object-detecting" in the sense used by web scripts, e.g., when
  * checking whether document.all is defined.
  */
 static bool
-Detecting(JSContext *cx, jsbytecode *pc)
+Detecting(JSContext *cx, JSScript *script, jsbytecode *pc)
 {
     /* General case: a branch or equality op follows the access. */
     JSOp op = JSOp(*pc);
     if (js_CodeSpec[op].format & JOF_DETECTING)
         return true;
 
-    JSAtom *atom;
-
-    JSScript *script = cx->stack.currentScript();
     jsbytecode *endpc = script->code + script->length;
     JS_ASSERT(script->code <= pc && pc < endpc);
 
     if (op == JSOP_NULL) {
         /*
          * Special case #1: handle (document.all == null).  Don't sweat
          * about JS1.2's revision of the equality operators here.
          */
@@ -2427,17 +2424,17 @@ Detecting(JSContext *cx, jsbytecode *pc)
     }
 
     if (op == JSOP_GETGNAME || op == JSOP_NAME) {
         /*
          * Special case #2: handle (document.all == undefined).  Don't worry
          * about a local variable named |undefined| shadowing the immutable
          * global binding...because, really?
          */
-        atom = script->getAtom(GET_UINT32_INDEX(pc));
+        JSAtom *atom = script->getAtom(GET_UINT32_INDEX(pc));
         if (atom == cx->runtime->atomState.typeAtoms[JSTYPE_VOID] &&
             (pc += js_CodeSpec[op].length) < endpc) {
             op = JSOp(*pc);
             return op == JSOP_EQ || op == JSOP_NE || op == JSOP_STRICTEQ || op == JSOP_STRICTNE;
         }
     }
 
     return false;
@@ -2445,34 +2442,36 @@ Detecting(JSContext *cx, jsbytecode *pc)
 
 /*
  * Infer lookup flags from the currently executing bytecode, returning
  * defaultFlags if a currently executing bytecode cannot be determined.
  */
 unsigned
 js_InferFlags(JSContext *cx, unsigned defaultFlags)
 {
-    const JSCodeSpec *cs;
-    uint32_t format;
+    /*
+     * Use ScriptFrameIter since we intentionally want to look across
+     * compartment boundaries in the case of cross-compartment property access.
+     */
+    ScriptFrameIter i(cx);
+    if (i.done())
+        return defaultFlags;
+
+    jsbytecode *pc = i.pc();
+    JSScript *script = i.script();
+    const JSCodeSpec *cs = &js_CodeSpec[*pc];
+    uint32_t format = cs->format;
     unsigned flags = 0;
-
-    jsbytecode *pc;
-    JSScript *script = cx->stack.currentScript(&pc);
-    if (!script || !pc)
-        return defaultFlags;
-
-    cs = &js_CodeSpec[*pc];
-    format = cs->format;
     if (JOF_MODE(format) != JOF_NAME)
         flags |= JSRESOLVE_QUALIFIED;
     if (format & JOF_SET) {
         flags |= JSRESOLVE_ASSIGNING;
     } else if (cs->length >= 0) {
         pc += cs->length;
-        if (pc < script->code + script->length && Detecting(cx, pc))
+        if (pc < script->code + script->length && Detecting(cx, script, pc))
             flags |= JSRESOLVE_DETECTING;
     }
     return flags;
 }
 
 /* static */ JSBool
 JSObject::nonNativeSetProperty(JSContext *cx, HandleObject obj,
                                HandleId id, MutableHandleValue vp, JSBool strict)
@@ -4353,17 +4352,17 @@ js_GetPropertyHelperInline(JSContext *cx
              * may be called from JS_GetMethodById. See bug 355145.
              */
             if (JSID_IS_ATOM(id, cx->runtime->atomState.iteratorIntrinsicAtom))
                 return JS_TRUE;
 
             /* Do not warn about tests like (obj[prop] == undefined). */
             if (cx->resolveFlags == RESOLVE_INFER) {
                 pc += js_CodeSpec[op].length;
-                if (Detecting(cx, pc))
+                if (Detecting(cx, script, pc))
                     return JS_TRUE;
             } else if (cx->resolveFlags & JSRESOLVE_DETECTING) {
                 return JS_TRUE;
             }
 
             unsigned flags = JSREPORT_WARNING | JSREPORT_STRICT;
             cx->stack.currentScript()->warnedAboutUndefinedProp = true;