Bug 1404107 - Fix cloning expando chains when reparenting DOM objects. r=bz,r=mrbkap

--HG--
extra : rebase_source : fac045a54af8fba9e3ac46012aaf3b8a4b7b480c
extra : source : 53838f13462feb5db5542ee6d5bc7e24172fb51f
This commit is contained in:
Jason Orendorff 2017-09-29 10:33:13 -05:00
parent 49b9ec94b3
commit f719f95f29
3 changed files with 29 additions and 40 deletions

View File

@ -2259,19 +2259,10 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg, ErrorResult& aErr
propertyHolder = nullptr;
}
// Expandos from other compartments are attached to the target JS object.
// Copy them over, and let the old ones die a natural death.
// Note that at this point the DOM_OBJECT_SLOT for |newobj| has not been set.
// CloneExpandoChain() will use this property of |newobj| when it calls
// preserveWrapper() via attachExpandoObject() if |aObj| has expandos set, and
// preserveWrapper() will not do anything in this case. This is safe because
// if expandos are present then the wrapper will already have been preserved
// for this native.
if (!xpc::XrayUtils::CloneExpandoChain(aCx, newobj, aObj)) {
aError.StealExceptionFromJSContext(aCx);
return;
}
// Grab a reference to the chain of objects that carry aObj's Xray expando
// properties (from all compartments). Transplanting will blow this away;
// we'll restore it manually afterwards.
JS::Rooted<JSObject*> expandoChain(aCx, xpc::XrayUtils::GetExpandoChain(aObj));
// We've set up |newobj|, so we make it own the native by setting its reserved
// slot and nulling out the reserved slot of |obj|.
@ -2288,6 +2279,14 @@ ReparentWrapper(JSContext* aCx, JS::Handle<JSObject*> aObjArg, ErrorResult& aErr
MOZ_CRASH();
}
// Copy Xray expando properties to the new wrapper.
if (!xpc::XrayUtils::CloneExpandoChain(aCx, aObj, expandoChain)) {
// Failure here means some expandos were not copied over. The object graph
// and the Xray machinery are left in a consistent state, but mysteriously
// losing these expandos is too weird to allow.
MOZ_CRASH();
}
nsWrapperCache* cache = nullptr;
CallQueryInterface(native, &cache);
bool preserving = cache->PreservingWrapper();

View File

@ -1241,30 +1241,12 @@ XrayTraits::ensureExpandoObject(JSContext* cx, HandleObject wrapper,
}
bool
XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject src)
XrayTraits::cloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject srcChain)
{
MOZ_ASSERT(js::IsObjectInContextCompartment(dst, cx));
MOZ_ASSERT(getExpandoChain(dst) == nullptr);
RootedObject oldHead(cx, getExpandoChain(src));
#ifdef DEBUG
// When this is called from dom::ReparentWrapper() there will be no native
// set for |dst|. Eventually it will be set to that of |src|. This will
// prevent attachExpandoObject() from preserving the wrapper, but this is
// not a problem because in this case the wrapper will already have been
// preserved when expandos were originally added to |src|. Assert the
// wrapper for |src| has been preserved if it has expandos set.
if (oldHead) {
nsISupports* identity = mozilla::dom::UnwrapDOMObjectToISupports(src);
if (identity) {
nsWrapperCache* cache = nullptr;
CallQueryInterface(identity, &cache);
MOZ_ASSERT_IF(cache, cache->PreservingWrapper());
}
}
#endif
RootedObject oldHead(cx, srcChain);
while (oldHead) {
RootedObject exclusive(cx, JS_GetReservedSlot(oldHead,
JSSLOT_EXPANDO_EXCLUSIVE_GLOBAL)
@ -1318,11 +1300,14 @@ XrayTraits::getExpandoClass(JSContext* cx, HandleObject target) const
}
namespace XrayUtils {
bool CloneExpandoChain(JSContext* cx, JSObject* dstArg, JSObject* srcArg)
JSObject* GetExpandoChain(HandleObject target)
{
RootedObject dst(cx, dstArg);
RootedObject src(cx, srcArg);
return GetXrayTraits(src)->cloneExpandoChain(cx, dst, src);
return GetXrayTraits(target)->getExpandoChain(target);
}
bool CloneExpandoChain(JSContext* cx, HandleObject dst, HandleObject srcChain)
{
return GetXrayTraits(dst)->cloneExpandoChain(cx, dst, srcChain);
}
} // namespace XrayUtils

View File

@ -35,9 +35,14 @@ namespace xpc {
namespace XrayUtils {
bool IsXPCWNHolderClass(const JSClass* clasp);
bool
IsXPCWNHolderClass(const JSClass* clasp);
bool CloneExpandoChain(JSContext* cx, JSObject* src, JSObject* dst);
JSObject*
GetExpandoChain(JS::HandleObject target);
bool
CloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject srcChain);
bool
IsTransparent(JSContext* cx, JS::HandleObject wrapper, JS::HandleId id);
@ -114,7 +119,7 @@ public:
JSObject* getExpandoChain(JS::HandleObject obj);
bool setExpandoChain(JSContext* cx, JS::HandleObject obj, JS::HandleObject chain);
bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject src);
bool cloneExpandoChain(JSContext* cx, JS::HandleObject dst, JS::HandleObject srcChain);
protected:
static const JSClass HolderClass;