Bug 731845 - XPCWrappedNative::ReparentWrapperIfFound should handle preserved wrappers. r=mrbkap

This commit is contained in:
Bobby Holley 2012-03-05 16:58:59 -08:00
parent c56541c485
commit 23e960e8cf
2 changed files with 45 additions and 19 deletions

View File

@ -597,29 +597,10 @@ nsNodeUtils::CloneAndAdopt(nsINode *aNode, bool aClone, bool aDeep,
if (aCx && wrapper) {
nsIXPConnect *xpc = nsContentUtils::XPConnect();
if (xpc) {
JSObject *preservedWrapper = nsnull;
// If reparenting moves us to a new compartment, preserving causes
// problems. In that case, we release ourselves and re-preserve after
// reparenting so we're sure to have the right JS object preserved.
// We use a JSObject stack copy of the wrapper to protect it from GC
// under ReparentWrappedNativeIfFound.
if (aNode->PreservingWrapper()) {
preservedWrapper = wrapper;
nsContentUtils::ReleaseWrapper(aNode, aNode);
NS_ASSERTION(aNode->GetWrapper(),
"ReleaseWrapper cleared our wrapper, this code needs to "
"be changed to deal with that!");
}
nsCOMPtr<nsIXPConnectJSObjectHolder> oldWrapper;
rv = xpc->ReparentWrappedNativeIfFound(aCx, wrapper, aNewScope, aNode,
getter_AddRefs(oldWrapper));
if (preservedWrapper) {
nsContentUtils::PreserveWrapper(aNode, aNode);
}
if (NS_FAILED(rv)) {
aNode->mNodeInfo.swap(nodeInfo);

View File

@ -53,6 +53,8 @@
#include "WrapperFactory.h"
#include "dombindings.h"
#include "nsContentUtils.h"
#include "mozilla/Util.h"
bool
@ -1479,6 +1481,43 @@ XPCWrappedNative::SystemIsBeingShutDown()
/***************************************************************************/
// If we have to transplant an object across compartments, we need to be
// careful if the underlying object implements nsWrapperCache and is preserving
// the wrapper.
//
// The class brackets a pair of Unpreserve/Preserve calls in the given scope.
//
// This class _must_ live on the stack, in part so that mPreservedWrapper is
// visible to the stack scanner. The caller wants the wrapper to be preserved,
// so we don't want it to get accidentally GCed.
class AutoWrapperChanger NS_STACK_CLASS {
public:
AutoWrapperChanger() : mCache(nsnull)
, mCOMObj(nsnull)
, mPreservedWrapper(nsnull)
{}
void init(nsISupports* aCOMObj, nsWrapperCache* aWrapperCache) {
mCOMObj = aCOMObj;
mCache = aWrapperCache;
if (mCache->PreservingWrapper()) {
mPreservedWrapper = mCache->GetWrapper();
MOZ_ASSERT(mPreservedWrapper);
nsContentUtils::ReleaseWrapper(mCOMObj, mCache);
}
}
~AutoWrapperChanger() {
if (mPreservedWrapper)
nsContentUtils::PreserveWrapper(mCOMObj, mCache);
}
private:
nsWrapperCache* mCache;
nsISupports* mCOMObj;
JSObject* mPreservedWrapper;
};
// static
nsresult
XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
@ -1497,10 +1536,16 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx,
nsresult rv;
nsRefPtr<XPCWrappedNative> wrapper;
AutoWrapperChanger wrapperChanger;
JSObject *flat;
nsWrapperCache* cache = nsnull;
CallQueryInterface(aCOMObj, &cache);
if (cache) {
// There's a wrapper cache. Make sure we keep it sane no matter what
// happens.
wrapperChanger.init(aCOMObj, cache);
flat = cache->GetWrapper();
if (flat && !IS_SLIM_WRAPPER_OBJECT(flat)) {
wrapper = static_cast<XPCWrappedNative*>(xpc_GetJSPrivate(flat));