Bug 1481793 part 3 - Assert cross-compartment wrappers don't wrap other CCWs. r=luke
authorJan de Mooij <jdemooij@mozilla.com>
Thu, 09 Aug 2018 13:34:40 +0200
changeset 485926 b1bfefd4495f785edec66dcec131f498f234ba95
parent 485925 697419a81da4f0b4e3895ab86527df6c17897c11
child 485927 f95e8da173618fddb155faf7df34576857027b14
push id9719
push userffxbld-merge
push dateFri, 24 Aug 2018 17:49:46 +0000
treeherdermozilla-beta@719ec98fba77 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersluke
bugs1481793
milestone63.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 1481793 part 3 - Assert cross-compartment wrappers don't wrap other CCWs. r=luke
js/src/jit/CacheIR.cpp
js/src/proxy/CrossCompartmentWrapper.cpp
js/src/proxy/Wrapper.cpp
--- a/js/src/jit/CacheIR.cpp
+++ b/js/src/jit/CacheIR.cpp
@@ -1098,25 +1098,27 @@ GetPropIRGenerator::tryAttachCrossCompar
 
     // If we're megamorphic prefer a generic proxy stub that handles a lot more
     // cases.
     if (mode_ == ICState::Mode::Megamorphic)
         return false;
 
     RootedObject unwrapped(cx_, Wrapper::wrappedObject(obj));
     MOZ_ASSERT(unwrapped == UnwrapOneChecked(obj));
+    MOZ_ASSERT(!IsCrossCompartmentWrapper(unwrapped),
+               "CCWs must not wrap other CCWs");
 
     // If we allowed different zones we would have to wrap strings.
     if (unwrapped->compartment()->zone() != cx_->compartment()->zone())
         return false;
 
     // Take the unwrapped object's global, and wrap in a
     // this-compartment wrapper. This is what will be stored in the IC
     // keep the compartment alive.
-    RootedObject wrappedTargetGlobal(cx_, &unwrapped->deprecatedGlobal());
+    RootedObject wrappedTargetGlobal(cx_, &unwrapped->nonCCWGlobal());
     if (!cx_->compartment()->wrap(cx_, &wrappedTargetGlobal))
         return false;
 
     bool isWindowProxy = false;
     RootedShape shape(cx_);
     RootedNativeObject holder(cx_);
 
     // Enter realm of target since some checks have side-effects
--- a/js/src/proxy/CrossCompartmentWrapper.cpp
+++ b/js/src/proxy/CrossCompartmentWrapper.cpp
@@ -602,17 +602,16 @@ js::RemapWrapper(JSContext* cx, JSObject
     RootedObject newTarget(cx, newTargetArg);
     MOZ_ASSERT(wobj->is<CrossCompartmentWrapperObject>());
     MOZ_ASSERT(!newTarget->is<CrossCompartmentWrapperObject>());
     JSObject* origTarget = Wrapper::wrappedObject(wobj);
     MOZ_ASSERT(origTarget);
     MOZ_ASSERT(!JS_IsDeadWrapper(origTarget),
                "We don't want a dead proxy in the wrapper map");
     Value origv = ObjectValue(*origTarget);
-    Realm* wrealm = wobj->deprecatedRealm();
     JS::Compartment* wcompartment = wobj->compartment();
 
     AutoDisableProxyCheck adpc;
 
     // If we're mapping to a different target (as opposed to just recomputing
     // for the same target), we must not have an existing wrapper for the new
     // target, otherwise this will break.
     MOZ_ASSERT_IF(origTarget != newTarget,
@@ -623,16 +622,20 @@ js::RemapWrapper(JSContext* cx, JSObject
     WrapperMap::Ptr p = wcompartment->lookupWrapper(origv);
     MOZ_ASSERT(&p->value().unsafeGet()->toObject() == wobj);
     wcompartment->removeWrapper(p);
 
     // When we remove origv from the wrapper map, its wrapper, wobj, must
     // immediately cease to be a cross-compartment wrapper. Nuke it.
     NukeCrossCompartmentWrapper(cx, wobj);
 
+    // wobj is no longer a cross-compartment wrapper after nuking it, so we can
+    // now use nonCCWRealm.
+    Realm* wrealm = wobj->nonCCWRealm();
+
     // First, we wrap it in the new compartment. We try to use the existing
     // wrapper, |wobj|, since it's been nuked anyway. The wrap() function has
     // the choice to reuse |wobj| or not.
     RootedObject tobj(cx, newTarget);
     AutoRealmUnchecked ar(cx, wrealm);
     if (!wcompartment->rewrap(cx, &tobj, wobj))
         MOZ_CRASH();
 
--- a/js/src/proxy/Wrapper.cpp
+++ b/js/src/proxy/Wrapper.cpp
@@ -335,16 +335,21 @@ Wrapper::wrappedObject(JSObject* wrapper
     MOZ_ASSERT(wrapper->is<WrapperObject>());
     JSObject* target = wrapper->as<ProxyObject>().target();
 
     // Eagerly unmark gray wrapper targets so we can assert that we don't create
     // black to gray edges. An incremental GC will eventually mark the targets
     // of black wrappers black but while it is in progress we can observe gray
     // targets. Expose rather than returning a gray object in this case.
     if (target) {
+        // A cross-compartment wrapper should never wrap a CCW. We rely on this
+        // in the wrapper handlers (we use AutoRealm on our return value, and
+        // AutoRealm cannot be used with CCWs).
+        MOZ_ASSERT_IF(IsCrossCompartmentWrapper(wrapper),
+                      !IsCrossCompartmentWrapper(target));
         if (wrapper->isMarkedBlack())
             MOZ_ASSERT(JS::ObjectIsNotGray(target));
         if (!wrapper->isMarkedGray())
             JS::ExposeObjectToActiveJS(target);
     }
 
     return target;
 }