Bug 734475 - Take the full union of native sets when bringing non-PreCreate XPWNs across compartments. r=mrbkap

This commit is contained in:
Bobby Holley 2012-03-16 12:47:20 -07:00
parent aaaa3c0e75
commit e2e6e39b20
3 changed files with 74 additions and 2 deletions

View File

@ -665,6 +665,54 @@ XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx,
return set;
}
// static
XPCNativeSet*
XPCNativeSet::GetNewOrUsed(XPCCallContext& ccx,
XPCNativeSet* firstSet,
XPCNativeSet* secondSet,
bool preserveFirstSetOrder)
{
// Figure out how many interfaces we'll need in the new set.
PRUint32 uniqueCount = firstSet->mInterfaceCount;
for (PRUint32 i = 0; i < secondSet->mInterfaceCount; ++i) {
if (!firstSet->HasInterface(secondSet->mInterfaces[i]))
uniqueCount++;
}
// If everything in secondSet was a duplicate, we can just use the first
// set.
if (uniqueCount == firstSet->mInterfaceCount)
return firstSet;
// If the secondSet is just a superset of the first, we can use it provided
// that the caller doesn't care about ordering.
if (!preserveFirstSetOrder && uniqueCount == secondSet->mInterfaceCount)
return secondSet;
// Ok, darn. Now we have to make a new set.
//
// It would be faster to just create the new set all at once, but that
// would involve wrangling with some pretty hairy code - especially since
// a lot of stuff assumes that sets are created by adding one interface to an
// existing set. So let's just do the slow and easy thing and hope that the
// above optimizations handle the common cases.
XPCNativeSet* currentSet = firstSet;
for (PRUint32 i = 0; i < secondSet->mInterfaceCount; ++i) {
XPCNativeInterface* iface = secondSet->mInterfaces[i];
if (!currentSet->HasInterface(iface)) {
// Create a new augmented set, inserting this interface at the end.
PRUint32 pos = currentSet->mInterfaceCount;
currentSet = XPCNativeSet::GetNewOrUsed(ccx, currentSet, iface, pos);
if (!currentSet)
return nsnull;
}
}
// We've got the union set. Hand it back to the caller.
MOZ_ASSERT(currentSet->mInterfaceCount == uniqueCount);
return currentSet;
}
// static
XPCNativeSet*
XPCNativeSet::NewInstance(XPCCallContext& ccx,

View File

@ -1882,6 +1882,18 @@ public:
XPCNativeInterface* newInterface,
PRUint16 position);
// This generates a union set.
//
// If preserveFirstSetOrder is true, the elements from |firstSet| come first,
// followed by any non-duplicate items from |secondSet|. If false, the same
// algorithm is applied; but if we detect that |secondSet| is a superset of
// |firstSet|, we return |secondSet| without worrying about whether the
// ordering might differ from |firstSet|.
static XPCNativeSet* GetNewOrUsed(XPCCallContext& ccx,
XPCNativeSet* firstSet,
XPCNativeSet* secondSet,
bool preserveFirstSetOrder);
static void ClearCacheEntryForClassInfo(nsIClassInfo* classInfo);
inline JSBool FindMember(jsid name, XPCNativeMember** pMember,

View File

@ -236,9 +236,21 @@ WrapperFactory::PrepareForWrapping(JSContext *cx, JSObject *scope, JSObject *obj
obj = JSVAL_TO_OBJECT(v);
NS_ASSERTION(IS_WN_WRAPPER(obj), "bad object");
// Because the underlying native didn't have a PreCreate hook, we had
// to a new (or possibly pre-existing) XPCWN in our compartment.
// This could be a problem for chrome code that passes XPCOM objects
// across compartments, because the effects of QI would disappear across
// compartments.
//
// So whenever we pull an XPCWN across compartments in this manner, we
// give the destination object the union of the two native sets. We try
// to do this cleverly in the common case to avoid too much overhead.
XPCWrappedNative *newwn = static_cast<XPCWrappedNative *>(xpc_GetJSPrivate(obj));
if (newwn->GetSet()->GetInterfaceCount() < wn->GetSet()->GetInterfaceCount())
newwn->SetSet(wn->GetSet());
XPCNativeSet *unionSet = XPCNativeSet::GetNewOrUsed(ccx, newwn->GetSet(),
wn->GetSet(), false);
if (!unionSet)
return nsnull;
newwn->SetSet(unionSet);
}
return DoubleWrap(cx, obj, flags);