Bug 922009 - MOZ_CRASH when trying to transplant objects with SCSWs. r=mrbkap
authorBobby Holley <bobbyholley@gmail.com>
Thu, 17 Oct 2013 10:00:02 +0200
changeset 165877 8fd2088036f2f170e2a9df8e02fd1e8871b90de5
parent 165876 22e6993216a9864e0ecc243efb10b977ddfaaeca
child 165878 f3f9a19a57b95c54f37aa675cf571c1d838f77b0
push id428
push userbbajaj@mozilla.com
push dateTue, 28 Jan 2014 00:16:25 +0000
treeherdermozilla-release@cd72a7ff3a75 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmrbkap
bugs922009
milestone27.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 922009 - MOZ_CRASH when trying to transplant objects with SCSWs. r=mrbkap
dom/bindings/BindingUtils.cpp
js/src/jsapi.cpp
js/src/jsapi.h
js/xpconnect/src/XPCWrappedNative.cpp
js/xpconnect/src/xpcpublic.h
js/xpconnect/tests/mochitest/file_nac.xhtml
js/xpconnect/tests/mochitest/mochitest.ini
js/xpconnect/tests/mochitest/test_nac.xhtml
js/xpconnect/wrappers/WrapperFactory.cpp
--- a/dom/bindings/BindingUtils.cpp
+++ b/dom/bindings/BindingUtils.cpp
@@ -1751,30 +1751,19 @@ ReparentWrapper(JSContext* aCx, JS::Hand
     js::SetReservedSlot(aObj, DOM_OBJECT_SLOT, JS::PrivateValue(nullptr));
   }
 
   nsWrapperCache* cache = nullptr;
   CallQueryInterface(native, &cache);
   if (ww != aObj) {
     MOZ_ASSERT(cache->HasSystemOnlyWrapper());
 
-    JS::RootedObject newwrapper(aCx,
-      xpc::WrapperFactory::WrapSOWObject(aCx, newobj));
-    if (!newwrapper) {
-      MOZ_CRASH();
-    }
+    // Oops. We don't support transplanting objects with SOWs anymore.
+    MOZ_CRASH();
 
-    // Ok, now we do the special object-plus-wrapper transplant.
-    ww = xpc::TransplantObjectWithWrapper(aCx, aObj, ww, newobj, newwrapper);
-    if (!ww) {
-      MOZ_CRASH();
-    }
-
-    aObj = newobj;
-    SetSystemOnlyWrapperSlot(aObj, JS::ObjectValue(*ww));
   } else {
     aObj = xpc::TransplantObject(aCx, aObj, newobj);
     if (!aObj) {
       MOZ_CRASH();
     }
   }
 
   bool preserving = cache->PreservingWrapper();
--- a/js/src/jsapi.cpp
+++ b/js/src/jsapi.cpp
@@ -1263,106 +1263,16 @@ JS_TransplantObject(JSContext *cx, Handl
     }
 
     // The new identity object might be one of several things. Return it to avoid
     // ambiguity.
     return newIdentity;
 }
 
 /*
- * Some C++ objects (such as the location object and XBL) require both an XPConnect
- * reflector and a security wrapper for that reflector. We expect that there are
- * no live references to the reflector, so when we perform the transplant we turn
- * the security wrapper into a cross-compartment wrapper. Just in case there
- * happen to be live references to the reflector, we swap it out to limit the harm.
- */
-JS_FRIEND_API(JSObject *)
-js_TransplantObjectWithWrapper(JSContext *cx,
-                               HandleObject origobj,
-                               HandleObject origwrapper,
-                               HandleObject targetobj,
-                               HandleObject targetwrapper)
-{
-    AutoMaybeTouchDeadZones agc(cx);
-    AutoDisableProxyCheck adpc(cx->runtime());
-
-    AssertHeapIsIdle(cx);
-    JS_ASSERT(!origobj->is<CrossCompartmentWrapperObject>());
-    JS_ASSERT(!origwrapper->is<CrossCompartmentWrapperObject>());
-    JS_ASSERT(!targetobj->is<CrossCompartmentWrapperObject>());
-    JS_ASSERT(!targetwrapper->is<CrossCompartmentWrapperObject>());
-
-    RootedObject newWrapper(cx);
-    JSCompartment *destination = targetobj->compartment();
-
-    // |origv| is the map entry we're looking up. The map entries are going to
-    // be for |origobj|, not |origwrapper|.
-    Value origv = ObjectValue(*origobj);
-
-    // There might already be a wrapper for the original object in the new
-    // compartment.
-    if (WrapperMap::Ptr p = destination->lookupWrapper(origv)) {
-        // There is. Make the existing cross-compartment wrapper a same-
-        // compartment wrapper.
-        newWrapper = &p->value.toObject();
-
-        // When we remove origv from the wrapper map, its wrapper, newWrapper,
-        // must immediately cease to be a cross-compartment wrapper. Neuter it.
-        destination->removeWrapper(p);
-        NukeCrossCompartmentWrapper(cx, newWrapper);
-
-        if (!JSObject::swap(cx, newWrapper, targetwrapper))
-            MOZ_CRASH();
-    } else {
-        // Otherwise, use the passed-in wrapper as the same-compartment wrapper.
-        newWrapper = targetwrapper;
-    }
-
-    // Now, iterate through other scopes looking for references to the old
-    // object. Note that the entries in the maps are for |origobj| and not
-    // |origwrapper|. They need to be updated to point at the new object.
-    if (!RemapAllWrappersForObject(cx, origobj, targetobj))
-        MOZ_CRASH();
-
-    // Lastly, update things in the original compartment. Our invariants dictate
-    // that the original compartment can only have one cross-compartment wrapper
-    // to the new object. So we choose to update |origwrapper|, not |origobj|,
-    // since there are probably no live direct intra-compartment references to
-    // |origobj|.
-    {
-        AutoCompartment ac(cx, origobj);
-
-        // We can't be sure that the reflector is completely dead. This is bad,
-        // because it is in a weird state. To minimize potential harm we create
-        // a new unreachable dummy object and swap it with the reflector.
-        // After the swap we have a possibly-live object that isn't dangerous,
-        // and a possibly-dangerous object that isn't live.
-        ProxyOptions options;
-        if (!IsBackgroundFinalized(origobj->tenuredGetAllocKind()))
-            options.setForceForegroundFinalization(true);
-        RootedObject reflectorGuts(cx, NewDeadProxyObject(cx, JS_GetGlobalForObject(cx, origobj),
-                                                          options));
-        if (!reflectorGuts || !JSObject::swap(cx, origobj, reflectorGuts))
-            MOZ_CRASH();
-
-        // Turn origwrapper into a CCW to the new object.
-        RootedObject wrapperGuts(cx, targetobj);
-        if (!JS_WrapObject(cx, &wrapperGuts))
-            MOZ_CRASH();
-        JS_ASSERT(Wrapper::wrappedObject(wrapperGuts) == targetobj);
-        if (!JSObject::swap(cx, origwrapper, wrapperGuts))
-            MOZ_CRASH();
-        origwrapper->compartment()->putWrapper(ObjectValue(*targetobj),
-                                               ObjectValue(*origwrapper));
-    }
-
-    return newWrapper;
-}
-
-/*
  * Recompute all cross-compartment wrappers for an object, resetting state.
  * Gecko uses this to clear Xray wrappers when doing a navigation that reuses
  * the inner window and global object.
  */
 JS_PUBLIC_API(bool)
 JS_RefreshCrossCompartmentWrappers(JSContext *cx, JSObject *objArg)
 {
     RootedObject obj(cx, objArg);
--- a/js/src/jsapi.h
+++ b/js/src/jsapi.h
@@ -1763,23 +1763,16 @@ extern JS_PUBLIC_API(bool)
 JS_WrapValue(JSContext *cx, jsval *vp);
 
 extern JS_PUBLIC_API(bool)
 JS_WrapId(JSContext *cx, jsid *idp);
 
 extern JS_PUBLIC_API(JSObject *)
 JS_TransplantObject(JSContext *cx, JS::Handle<JSObject*> origobj, JS::Handle<JSObject*> target);
 
-extern JS_FRIEND_API(JSObject *)
-js_TransplantObjectWithWrapper(JSContext *cx,
-                               JS::Handle<JSObject*> origobj,
-                               JS::Handle<JSObject*> origwrapper,
-                               JS::Handle<JSObject*> targetobj,
-                               JS::Handle<JSObject*> targetwrapper);
-
 extern JS_PUBLIC_API(bool)
 JS_RefreshCrossCompartmentWrappers(JSContext *cx, JSObject *ob);
 
 /*
  * At any time, a JSContext has a current (possibly-nullptr) compartment.
  * Compartments are described in:
  *
  *   developer.mozilla.org/en-US/docs/SpiderMonkey/SpiderMonkey_compartments
--- a/js/xpconnect/src/XPCWrappedNative.cpp
+++ b/js/xpconnect/src/XPCWrappedNative.cpp
@@ -1458,28 +1458,20 @@ XPCWrappedNative::ReparentWrapperIfFound
             if (!newMap->Add(wrapper))
                 MOZ_CRASH();
         }
 
         RootedObject ww(cx, wrapper->GetWrapper());
         if (ww) {
             RootedObject newwrapper(cx);
             MOZ_ASSERT(wrapper->NeedsSOW(), "weird wrapper wrapper");
-            newwrapper = xpc::WrapperFactory::WrapSOWObject(cx, newobj);
-            if (!newwrapper)
-                MOZ_CRASH();
-
-            // Ok, now we do the special object-plus-wrapper transplant.
-            ww = xpc::TransplantObjectWithWrapper(cx, flat, ww, newobj,
-                                                  newwrapper);
-            if (!ww)
-                MOZ_CRASH();
-
-            flat = newobj;
-            wrapper->SetWrapper(ww);
+
+            // Oops. We don't support transplanting objects with SOWs anymore.
+            MOZ_CRASH();
+
         } else {
             flat = xpc::TransplantObject(cx, flat, newobj);
             if (!flat)
                 MOZ_CRASH();
         }
 
         MOZ_ASSERT(flat);
         wrapper->mFlatJSObject = flat;
--- a/js/xpconnect/src/xpcpublic.h
+++ b/js/xpconnect/src/xpcpublic.h
@@ -33,21 +33,16 @@ class nsIGlobalObject;
 #ifndef BAD_TLS_INDEX
 #define BAD_TLS_INDEX ((uint32_t) -1)
 #endif
 
 namespace xpc {
 JSObject *
 TransplantObject(JSContext *cx, JS::HandleObject origobj, JS::HandleObject target);
 
-JSObject *
-TransplantObjectWithWrapper(JSContext *cx,
-                            JS::HandleObject origobj, JS::HandleObject origwrapper,
-                            JS::HandleObject targetobj, JS::HandleObject targetwrapper);
-
 // Return a raw XBL scope object corresponding to contentScope, which must
 // be an object whose global is a DOM window.
 //
 // The return value is not wrapped into cx->compartment, so be sure to enter
 // its compartment before doing anything meaningful.
 //
 // Also note that XBL scopes are lazily created, so the return-value should be
 // null-checked unless the caller can ensure that the scope must already
deleted file mode 100644
--- a/js/xpconnect/tests/mochitest/file_nac.xhtml
+++ /dev/null
@@ -1,21 +0,0 @@
-<html xmlns="http://www.w3.org/1999/xhtml">
-<head>
-  <bindings xmlns="http://www.mozilla.org/xbl"
-            xmlns:html="http://www.w3.org/1999/xhtml">
-    <binding id="testBinding2">
-      <implementation>
-        <constructor>
-          document.body.appendChild(parent.wrappedJSObject.nac);
-          parent.wrappedJSObject.ok(true, "Didn't crash");
-          parent.wrappedJSObject.SimpleTest.finish();
-        </constructor>
-      </implementation>
-    </binding>
-  </bindings>
-<script type="application/javascript">
-</script>
-</head>
-<body>
-<div id="bindingSink" style="-moz-binding: url(#testBinding2);"></div>
-</body>
-</html>
--- a/js/xpconnect/tests/mochitest/mochitest.ini
+++ b/js/xpconnect/tests/mochitest/mochitest.ini
@@ -25,17 +25,16 @@ support-files =
   file_crosscompartment_weakmap.html
   file_documentdomain.html
   file_doublewrappedcompartments.html
   file_empty.html
   file_evalInSandbox.html
   file_exnstack.html
   file_expandosharing.html
   file_mozMatchesSelector.html
-  file_nac.xhtml
   file_nodelists.html
   file_wrappers-2.html
   inner.html
   test1_bug629331.html
   test2_bug629331.html
 
 [test_asmjs.html]
 [test_bug384632.html]
--- a/js/xpconnect/tests/mochitest/test_nac.xhtml
+++ b/js/xpconnect/tests/mochitest/test_nac.xhtml
@@ -40,21 +40,17 @@ https://bugzilla.mozilla.org/show_bug.cg
   function playWithNAC(nac) {
     checkThrows(function() { nac.toString(); });
     checkThrows(function() { nac.textContent; });
     var iwin = document.getElementById('ifr').contentWindow;
     iwin.nac = window.nac = nac;
     checkThrows(new iwin.Function('nac.toString();'));
     checkThrows(new iwin.Function('nac.textContent;'));
 
-    // Try adopting the NAC into another scope using a different XBL binding.
-    // The <constructor> in file_nac.xhtml will call SimpleTest.finish().
-    var ifr2 = document.createElement('iframe');
-    document.body.appendChild(ifr2);
-    ifr2.contentWindow.location = 'file_nac.xhtml';
+    SimpleTest.finish();
   }
 
   ]]>
 </script>
 </head>
 <body>
 <a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=914618">Mozilla Bug 914618</a>
 <p id="display"></p>
--- a/js/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/xpconnect/wrappers/WrapperFactory.cpp
@@ -662,35 +662,16 @@ TransplantObject(JSContext *cx, JS::Hand
     if (!newIdentity || !oldWaiver)
        return newIdentity;
 
     if (!FixWaiverAfterTransplant(cx, oldWaiver, newIdentity))
         return nullptr;
     return newIdentity;
 }
 
-JSObject *
-TransplantObjectWithWrapper(JSContext *cx,
-                            HandleObject origobj, HandleObject origwrapper,
-                            HandleObject targetobj, HandleObject targetwrapper)
-{
-    RootedObject oldWaiver(cx, WrapperFactory::GetXrayWaiver(origobj));
-    RootedObject newSameCompartmentWrapper(cx,
-      js_TransplantObjectWithWrapper(cx, origobj, origwrapper, targetobj,
-                                     targetwrapper));
-    if (!newSameCompartmentWrapper || !oldWaiver)
-        return newSameCompartmentWrapper;
-
-    RootedObject newIdentity(cx, Wrapper::wrappedObject(newSameCompartmentWrapper));
-    MOZ_ASSERT(!js::IsWrapper(newIdentity));
-    if (!FixWaiverAfterTransplant(cx, oldWaiver, newIdentity))
-        return nullptr;
-    return newSameCompartmentWrapper;
-}
-
 nsIGlobalObject *
 GetNativeForGlobal(JSObject *obj)
 {
     MOZ_ASSERT(JS_IsGlobalObject(obj));
     if (!EnsureCompartmentPrivate(obj)->scope)
         return nullptr;
 
     // Every global needs to hold a native as its private.