Fix for bug 842799 (|Document.prototype instanceof Node| inside <script> returns false). r=bz.
authorPeter Van der Beken <peterv@propagandism.org>
Fri, 22 Feb 2013 10:25:24 +0100
changeset 123466 9f2f90b7c78bfa817519c7978e2a5dc4a6df5739
parent 123465 cf5ac264118b80cf8b774ce97daf025d6e49ea8a
child 123467 84b9049008e940bcfea9132e82e5866c851edea4
push id24382
push userryanvm@gmail.com
push dateFri, 01 Mar 2013 23:43:19 +0000
treeherdermozilla-central@3362afba690e [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz
bugs842799
milestone22.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
Fix for bug 842799 (|Document.prototype instanceof Node| inside <script> returns false). r=bz.
dom/bindings/BindingUtils.cpp
dom/bindings/Codegen.py
dom/bindings/test/Makefile.in
dom/bindings/test/file_InstanceOf.html
dom/bindings/test/test_InstanceOf.html
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1591,33 +1591,62 @@ WorkerGlobalObject::WorkerGlobalObject(J
 
 JSBool
 InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSObject* instance,
                      JSBool* bp)
 {
   const DOMIfaceAndProtoJSClass* clasp =
     DOMIfaceAndProtoJSClass::FromJSClass(js::GetObjectClass(obj));
 
-  const DOMClass* domClass = GetDOMClass(instance);
+  const DOMClass* domClass = GetDOMClass(js::UnwrapObject(instance));
 
   MOZ_ASSERT(!domClass || clasp->mPrototypeID != prototypes::id::_ID_Count,
              "Why do we have a hasInstance hook if we don't have a prototype "
              "ID?");
-  *bp = domClass &&
-        domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID;
+
+  if (domClass &&
+      domClass->mInterfaceChain[clasp->mDepth] == clasp->mPrototypeID) {
+    *bp = true;
+    return true;
+  }
+
+  jsval protov;
+  DebugOnly<bool> ok = JS_GetProperty(cx, obj, "prototype", &protov);
+  MOZ_ASSERT(ok, "Someone messed with our prototype property?");
+
+  JSObject *interfacePrototype = &protov.toObject();
+  MOZ_ASSERT(IsDOMIfaceAndProtoClass(js::GetObjectClass(interfacePrototype)),
+             "Someone messed with our prototype property?");
 
+  JSObject* proto;
+  if (!JS_GetPrototype(cx, instance, &proto)) {
+    return false;
+  }
+
+  while (proto) {
+    if (proto == interfacePrototype) {
+      *bp = true;
+      return true;
+    }
+
+    if (!JS_GetPrototype(cx, proto, &proto)) {
+      return false;
+    }
+  }
+
+  *bp = false;
   return true;
 }
 
 JSBool
 InterfaceHasInstance(JSContext* cx, JSHandleObject obj, JSMutableHandleValue vp,
                      JSBool* bp)
 {
   if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
-  return InterfaceHasInstance(cx, obj, js::UnwrapObject(&vp.toObject()), bp);
+  return InterfaceHasInstance(cx, obj, &vp.toObject(), bp);
 }
 
 } // namespace dom
 } // namespace mozilla
--- a/dom/bindings/Codegen.py
+++ b/dom/bindings/Codegen.py
@@ -1042,26 +1042,26 @@ class CGClassHasInstanceHook(CGAbstractS
 
     def generate_code(self):
         assert self.descriptor.nativeOwnership == 'nsisupports'
         return """  if (!vp.isObject()) {
     *bp = false;
     return true;
   }
 
-  JSObject* instance = js::UnwrapObject(&vp.toObject());
-
+  JSObject* instance = &vp.toObject();
   bool ok = InterfaceHasInstance(cx, obj, instance, bp);
   if (!ok || *bp) {
     return ok;
   }
 
   // FIXME Limit this to chrome by checking xpc::AccessCheck::isChrome(obj).
   nsISupports* native =
-    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, instance);
+    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx,
+                                                    js::UnwrapObject(instance));
   nsCOMPtr<nsIDOM%s> qiResult = do_QueryInterface(native);
   *bp = !!qiResult;
   return true;""" % self.descriptor.interface.identifier.name
 
 def isChromeOnly(m):
     return m.getExtendedAttribute("ChromeOnly")
 
 class MemberCondition:
--- a/dom/bindings/test/Makefile.in
+++ b/dom/bindings/test/Makefile.in
@@ -50,16 +50,17 @@ bindinggen_dependencies := \
 
 MOCHITEST_FILES := \
   test_bug773326.html \
   test_enums.html \
   test_integers.html \
   test_interfaceToString.html \
   test_lookupGetter.html \
   test_InstanceOf.html \
+  file_InstanceOf.html \
   test_traceProtos.html \
   test_forOf.html \
   forOf_iframe.html \
   test_sequence_wrapping.html \
   file_bug775543.html \
   test_bug788369.html \
   test_bug742191.html \
   test_namedNoIndexed.html \
new file mode 100644
--- /dev/null
+++ b/dom/bindings/test/file_InstanceOf.html
@@ -0,0 +1,12 @@
+<!DOCTYPE HTML>
+<html>
+<body>
+<script type="application/javascript">
+function runTest()
+{
+  return [ parent.HTMLElement.prototype instanceof Element,
+           parent.HTMLElement.prototype instanceof parent.Element ];
+}
+</script>
+</body>
+</html>
--- a/dom/bindings/test/test_InstanceOf.html
+++ b/dom/bindings/test/test_InstanceOf.html
@@ -8,21 +8,47 @@ https://bugzilla.mozilla.org/show_bug.cg
   <title>Test for Bug 748983</title>
   <script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
   <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=748983">Mozilla Bug 748983</a>
 <p id="display"></p>
 <div id="content" style="display: none">
-  
 </div>
 <pre id="test">
 <script type="application/javascript">
 
 /** Test for Bug 748983 **/
-ok(document instanceof EventTarget, "document is an event target")
-ok(new XMLHttpRequest() instanceof XMLHttpRequest, "instanceof should work on XHR");
+
+SimpleTest.waitForExplicitFinish();
+
+function runTest()
+{
+    ok(document instanceof EventTarget, "document is an event target")
+    ok(new XMLHttpRequest() instanceof XMLHttpRequest, "instanceof should work on XHR");
+    ok(HTMLElement.prototype instanceof Node, "instanceof needs to walk the prototype chain")
+
+    var otherWin = document.getElementById("testFrame").contentWindow;
+
+    ok(otherWin.HTMLElement.prototype instanceof otherWin.Node, "Same-origin instanceof of a interface prototype object should work, even if called cross-origin");
+    ok(!(otherWin.HTMLElement.prototype instanceof Node), "Cross-origin instanceof of a interface prototype object shouldn't work");
+
+    // We need to reset HTMLElement.prototype.__proto__ to the original value
+    // before using anything from the harness, otherwise the harness code breaks
+    // in weird ways.
+    HTMLElement.prototype.__proto__ = otherWin.Element.prototype;
+    var [ shouldSucceed, shouldFail ] = otherWin.runTest();
+    shouldSucceed = shouldSucceed && HTMLElement.prototype instanceof otherWin.Element;
+    shouldFail = shouldFail && HTMLElement.prototype instanceof Element;
+    HTMLElement.prototype.__proto__ = Element.prototype;
+
+    ok(shouldSucceed, "If an interface prototype object is on the protochain then instanceof with the interface object should succeed");
+    ok(!shouldFail, "If an interface prototype object is not on the protochain then instanceof with the interface object should succeed");
+
+    SimpleTest.finish();
+}
 
 </script>
 </pre>
+<iframe id="testFrame" src="file_InstanceOf.html" onload="runTest()"></iframe>
 </body>
 </html>