From 4dfe6493dace2e6e50f9c0a17d69541b3d4da99f Mon Sep 17 00:00:00 2001 From: "mrbkap@gmail.com" Date: Fri, 4 Jan 2008 20:45:16 -0800 Subject: [PATCH] Add a way to find all of the XOWs for an object and use it to deal with hard cases where we have to clear the scope of XOWs in order to reflect changes to the underlying object. Also deal with objects moving between scopes by ensuring that we're always able to find their XOWs. bug 399587, r+sr=jst r=brendan for some last-minute changes added in this version. --- content/html/document/src/nsHTMLDocument.cpp | 2 +- dom/src/base/nsDOMClassInfo.cpp | 37 +++--- js/src/xpconnect/idl/nsIXPConnect.idl | 25 +++- .../xpconnect/src/XPCCrossOriginWrapper.cpp | 108 +++++++++++------- js/src/xpconnect/src/XPCNativeWrapper.cpp | 21 ---- js/src/xpconnect/src/XPCWrapper.h | 4 + js/src/xpconnect/src/nsXPConnect.cpp | 58 +++++++++- js/src/xpconnect/src/xpcmaps.cpp | 94 ++++++++++++++- js/src/xpconnect/src/xpcmaps.h | 40 ++++--- js/src/xpconnect/src/xpcprivate.h | 1 + js/src/xpconnect/src/xpcwrappednative.cpp | 10 ++ .../xpconnect/src/xpcwrappednativescope.cpp | 1 + js/src/xpconnect/tests/mochitest/Makefile.in | 1 + .../tests/mochitest/test_bug393269.html | 46 ++++++++ 14 files changed, 346 insertions(+), 102 deletions(-) create mode 100644 js/src/xpconnect/tests/mochitest/test_bug393269.html diff --git a/content/html/document/src/nsHTMLDocument.cpp b/content/html/document/src/nsHTMLDocument.cpp index 6be529a5418..4743c4c011a 100644 --- a/content/html/document/src/nsHTMLDocument.cpp +++ b/content/html/document/src/nsHTMLDocument.cpp @@ -2155,7 +2155,7 @@ nsHTMLDocument::OpenCommon(const nsACString& aContentType, PRBool aReplace) NS_FAILED(callerPrincipal->Equals(NodePrincipal(), &samePrincipal)) || !samePrincipal) { SetIsInitialDocument(PR_FALSE); - } + } rv = window->SetNewDocument(this, nsnull, PR_FALSE); NS_ENSURE_SUCCESS(rv, rv); diff --git a/dom/src/base/nsDOMClassInfo.cpp b/dom/src/base/nsDOMClassInfo.cpp index 3d614c896e1..ebc4b650a6d 100644 --- a/dom/src/base/nsDOMClassInfo.cpp +++ b/dom/src/base/nsDOMClassInfo.cpp @@ -4737,6 +4737,21 @@ nsWindowSH::DelProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx, return NS_ERROR_DOM_SECURITY_ERR; } + // Notify any XOWs on our outer window. + + nsGlobalWindow *outerWin = win->GetOuterWindowInternal(); + if (outerWin) { + nsCOMPtr wn; + nsIXPConnect *xpc = nsContentUtils::XPConnect(); + nsresult rv = + xpc->GetWrappedNativeOfJSObject(cx, outerWin->GetGlobalJSObject(), + getter_AddRefs(wn)); + NS_ENSURE_SUCCESS(rv, rv); + + rv = xpc->UpdateXOWs(cx, wn, nsIXPConnect::XPC_XOW_CLEARSCOPE); + NS_ENSURE_SUCCESS(rv, rv); + } + return NS_OK; } @@ -5865,10 +5880,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, // a different context. if (!win->IsChromeWindow()) { - rv = sXPConnect->GetCrossOriginWrapperForObject(cx, - win->GetGlobalJSObject(), - JSVAL_TO_OBJECT(v), - &v); + rv = sXPConnect->GetXOWForObject(cx, win->GetGlobalJSObject(), + JSVAL_TO_OBJECT(v), &v); NS_ENSURE_SUCCESS(rv, rv); } @@ -5979,9 +5992,7 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, sDoSecurityCheckInAddProperty = PR_FALSE; if (!win->IsChromeWindow()) { - rv = sXPConnect->GetCrossOriginWrapperForObject(cx, scope, - JSVAL_TO_OBJECT(v), - &v); + rv = sXPConnect->GetXOWForObject(cx, scope, JSVAL_TO_OBJECT(v), &v); NS_ENSURE_SUCCESS(rv, rv); } @@ -6089,10 +6100,8 @@ nsWindowSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx, scope = oldWin->GetGlobalJSObject(); } - rv = sXPConnect->GetCrossOriginWrapperForObject(cx, - scope, - JSVAL_TO_OBJECT(winVal), - &winVal); + rv = sXPConnect->GetXOWForObject(cx, scope, JSVAL_TO_OBJECT(winVal), + &winVal); NS_ENSURE_SUCCESS(rv, rv); } PRBool ok = @@ -6302,7 +6311,7 @@ nsWindowSH::OuterObject(nsIXPConnectWrappedNative *wrapper, JSContext * cx, } scope = ::JS_GetGlobalForObject(cx, scope); jsval v; - rv = sXPConnect->GetCrossOriginWrapperForObject(cx, scope, winObj, &v); + rv = sXPConnect->GetXOWForObject(cx, scope, winObj, &v); *_retval = NS_SUCCEEDED(rv) ? JSVAL_TO_OBJECT(v) : nsnull; } @@ -7648,8 +7657,8 @@ nsDocumentSH::PostCreate(nsIXPConnectWrappedNative *wrapper, JSContext *cx, nsGlobalWindow *internalWin = static_cast(sgo); if (!internalWin->IsChromeWindow()) { - rv = sXPConnect->GetCrossOriginWrapperForObject(cx, sgo->GetGlobalJSObject(), - obj, &docVal); + rv = sXPConnect->GetXOWForObject(cx, sgo->GetGlobalJSObject(), obj, + &docVal); NS_ENSURE_SUCCESS(rv, rv); } diff --git a/js/src/xpconnect/idl/nsIXPConnect.idl b/js/src/xpconnect/idl/nsIXPConnect.idl index 56f09fd64be..f8bed33f559 100644 --- a/js/src/xpconnect/idl/nsIXPConnect.idl +++ b/js/src/xpconnect/idl/nsIXPConnect.idl @@ -447,7 +447,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports { 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } } %} -[uuid(8a47448a-66b0-4beb-a5a2-24f22e9c9dea)] +[uuid(20df9082-5b83-416d-ba80-0422af516d57)] interface nsIXPConnect : nsISupports { %{ C++ @@ -729,9 +729,26 @@ interface nsIXPConnect : nsISupports * @param aParent The parent to create the wrapper with. * @param aWrappedObj The object to wrap. */ - [noscript] JSVal getCrossOriginWrapperForObject(in JSContextPtr aJSContext, - in JSObjectPtr aParent, - in JSObjectPtr aWrappedObj); + [noscript] JSVal getXOWForObject(in JSContextPtr aJSContext, + in JSObjectPtr aParent, + in JSObjectPtr aWrappedObj); + + /** + * Tells updateXOWs to clear the scope of all of the XOWs it finds. + */ + const PRUint32 XPC_XOW_CLEARSCOPE = 1; + + /** + * Performs an operation over all of |object|'s XOWs such as clearing + * their scopes or updating their concept of the current principal. + * + * @param aJSContext A context to use to perform JS operations. + * @param aObject Which XPCWrappedNative we should find the XOWs for. + * @param aWay What operation to perform. + */ + [noscript] void updateXOWs(in JSContextPtr aJSContext, + in nsIXPConnectWrappedNative aObject, + in PRUint32 aWay); /** * Root JS objects held by aHolder. diff --git a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp index eb689a1b315..7c7c9981121 100644 --- a/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp +++ b/js/src/xpconnect/src/XPCCrossOriginWrapper.cpp @@ -191,6 +191,44 @@ GetSecurityManager() return gScriptSecurityManager; } +JSBool +XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj, + XPCWrappedNativeScope *newScope) +{ + typedef WrappedNative2WrapperMap::Link Link; + XPCJSRuntime *rt = nsXPConnect::GetRuntime(); + WrappedNative2WrapperMap *map = innerObj->GetScope()->GetWrapperMap(); + Link *link; + + { // Scoped lock + XPCAutoLock al(rt->GetMapLock()); + link = map->FindLink(innerObj->GetFlatJSObject()); + } + + if (!link) { + // No link here means that there were no XOWs for this object. + return JS_TRUE; + } + + JSObject *xow = link->obj; + + { // Scoped lock. + XPCAutoLock al(rt->GetMapLock()); + if (!newScope->GetWrapperMap()->AddLink(innerObj->GetFlatJSObject(), link)) + return JS_FALSE; + map->Remove(innerObj->GetFlatJSObject()); + } + + if (!xow) { + // Nothing else to do. + return JS_TRUE; + } + + return JS_SetReservedSlot(cx, xow, XPCWrapper::sNumSlots, + PRIVATE_TO_JSVAL(newScope)) && + JS_SetParent(cx, xow, newScope->GetGlobalJSObject()); +} + static JSBool IsValFrame(JSContext *cx, JSObject *obj, jsval v, XPCWrappedNative *wn) { @@ -433,43 +471,34 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp) XPCCallContext ccx(NATIVE_CALLER, cx); NS_ENSURE_TRUE(ccx.IsValid(), JS_FALSE); - XPCWrappedNativeScope *parentScope = - XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent); - XPCWrappedNativeScope *wrapperScope = wn->GetScope(); - -#ifdef DEBUG_mrbkap - printf("Wrapping object at %p (%s) [%p %p]\n", - (void *)wrappedObj, JS_GET_CLASS(cx, wrappedObj)->name, - (void *)parentScope, (void *)wrapperScope); -#endif - - JSObject *outerObj = nsnull; - JSBool sameOrigin = (parentScope == wrapperScope); - WrappedNative2WrapperMap *map = - sameOrigin ? wrapperScope->GetWrapperMap() : parentScope->GetWrapperMap(); - - if (sameOrigin) { - outerObj = wn->GetWrapper(); - if (outerObj && JS_GET_CLASS(cx, outerObj) == &sXPC_XOW_JSClass.base) { -#ifdef DEBUG_mrbkap - printf("But found a wrapper already there %p!\n", (void *)outerObj); -#endif - *vp = OBJECT_TO_JSVAL(outerObj); - return JS_TRUE; + // The parent must be the inner global object for its scope. + parent = JS_GetGlobalForObject(cx, parent); + JSClass *clasp = JS_GET_CLASS(cx, parent); + if (clasp->flags & JSCLASS_IS_EXTENDED) { + JSExtendedClass *xclasp = reinterpret_cast(clasp); + if (xclasp->innerObject) { + parent = xclasp->innerObject(cx, parent); + if (!parent) { + return JS_FALSE; + } } } + XPCWrappedNativeScope *parentScope = + XPCWrappedNativeScope::FindInJSObjectScope(ccx, parent); + +#ifdef DEBUG_mrbkap + printf("Wrapping object at %p (%s) [%p]\n", + (void *)wrappedObj, JS_GET_CLASS(cx, wrappedObj)->name, + (void *)parentScope); +#endif + + JSObject *outerObj = nsnull; + WrappedNative2WrapperMap *map = parentScope->GetWrapperMap(); + { // Scoped lock XPCAutoLock al(rt->GetMapLock()); - - if (outerObj) { - outerObj = map->Add(wrappedObj, outerObj); - if (sameOrigin) { - wn->SetWrapper(nsnull); - } - } else { - outerObj = map->Find(wrappedObj); - } + outerObj = map->Find(wrappedObj); } if (outerObj) { @@ -478,9 +507,6 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp) #ifdef DEBUG_mrbkap printf("But found a wrapper in the map %p!\n", (void *)outerObj); #endif - if (sameOrigin) { - wn->SetWrapper(outerObj); - } *vp = OBJECT_TO_JSVAL(outerObj); return JS_TRUE; } @@ -509,14 +535,10 @@ XPC_XOW_WrapObject(JSContext *cx, JSObject *parent, jsval *vp) } *vp = OBJECT_TO_JSVAL(outerObj); - if (!sameOrigin) { + + { // Scoped lock XPCAutoLock al(rt->GetMapLock()); - map->Add(wrappedObj, outerObj); - } else { -#ifdef DEBUG_mrbkap - printf("Setting wrapper to %p\n", (void *)outerObj); -#endif - wn->SetWrapper(outerObj); + map->Add(wn->GetScope()->GetWrapperMap(), wrappedObj, outerObj); } return JS_TRUE; @@ -860,7 +882,7 @@ XPC_XOW_Finalize(JSContext *cx, JSObject *obj) // entirely. Scope can be null if we're an enumerating XOW. XPCWrappedNativeScope *scope = reinterpret_cast (JSVAL_TO_PRIVATE(scopeVal)); - if (!scope || XPCWrappedNativeScope::IsDyingScope(scope)) { + if (!scope) { return; } diff --git a/js/src/xpconnect/src/XPCNativeWrapper.cpp b/js/src/xpconnect/src/XPCNativeWrapper.cpp index 35419b9af2d..e06006b0a9b 100644 --- a/js/src/xpconnect/src/XPCNativeWrapper.cpp +++ b/js/src/xpconnect/src/XPCNativeWrapper.cpp @@ -1080,28 +1080,7 @@ XPCNativeWrapper::GetNewOrUsed(JSContext *cx, XPCWrappedNative *wrapper) } JSObject *obj = wrapper->GetWrapper(); - if (obj && XPCNativeWrapper::IsNativeWrapper(cx, obj)) { - return obj; - } - - XPCWrappedNativeScope *scope = wrapper->GetScope(); - XPCJSRuntime *rt = nsXPConnect::GetRuntime(); - - { // Scoped lock. - XPCAutoLock al(rt->GetMapLock()); - - if (obj) { - obj = scope->GetWrapperMap()->Add(wrapper->GetFlatJSObject(), obj); - wrapper->SetWrapper(nsnull); - } else { - obj = scope->GetWrapperMap()->Find(wrapper->GetFlatJSObject()); - } - } - if (obj) { - NS_ASSERTION(XPCNativeWrapper::IsNativeWrapper(cx, obj), - "Weird object in the wrapper map"); - wrapper->SetWrapper(obj); return obj; } diff --git a/js/src/xpconnect/src/XPCWrapper.h b/js/src/xpconnect/src/XPCWrapper.h index 0e78f23d4dd..42771ac8c3f 100644 --- a/js/src/xpconnect/src/XPCWrapper.h +++ b/js/src/xpconnect/src/XPCWrapper.h @@ -74,6 +74,10 @@ XPC_XOW_WrapFunction(JSContext *cx, JSObject *wrapperObj, JSObject *funobj, JSBool XPC_XOW_RewrapIfNeeded(JSContext *cx, JSObject *wrapperObj, jsval *vp); +JSBool +XPC_XOW_WrapperMoved(JSContext *cx, XPCWrappedNative *innerObj, + XPCWrappedNativeScope *newScope); + nsresult IsWrapperSameOrigin(JSContext *cx, JSObject *wrappedObj); diff --git a/js/src/xpconnect/src/nsXPConnect.cpp b/js/src/xpconnect/src/nsXPConnect.cpp index 34b00545782..82a9a1b3dcb 100644 --- a/js/src/xpconnect/src/nsXPConnect.cpp +++ b/js/src/xpconnect/src/nsXPConnect.cpp @@ -1916,16 +1916,66 @@ nsXPConnect::GetWrappedNativePrototype(JSContext * aJSContext, /* [noscript] JSVal GetCrossOriginWrapperForValue(in JSContextPtr aJSContext, in JSVal aCurrentVal); */ NS_IMETHODIMP -nsXPConnect::GetCrossOriginWrapperForObject(JSContext * aJSContext, - JSObject * aParent, - JSObject * aWrappedObj, - jsval * rval) +nsXPConnect::GetXOWForObject(JSContext * aJSContext, + JSObject * aParent, + JSObject * aWrappedObj, + jsval * rval) { *rval = OBJECT_TO_JSVAL(aWrappedObj); return XPC_XOW_WrapObject(aJSContext, aParent, rval) ? NS_OK : NS_ERROR_FAILURE; } +static inline PRBool +PerformOp(JSContext *cx, PRUint32 aWay, JSObject *obj) +{ + NS_ASSERTION(aWay == nsIXPConnect::XPC_XOW_CLEARSCOPE, + "Nothing else is implemented yet"); + + JS_ClearScope(cx, obj); + return PR_TRUE; +} + +/* [noscript] void updateXOWs (in JSContextPtr aJSContext, + * in nsIXPConnectJSObjectHolder aObject, + * in PRUint32 aWay); */ +NS_IMETHODIMP +nsXPConnect::UpdateXOWs(JSContext* aJSContext, + nsIXPConnectWrappedNative* aObject, + PRUint32 aWay) +{ + typedef WrappedNative2WrapperMap::Link Link; + XPCWrappedNative* wn = static_cast(aObject); + XPCWrappedNativeScope* scope = wn->GetScope(); + WrappedNative2WrapperMap* map = scope->GetWrapperMap(); + Link* list; + + { + XPCJSRuntime* rt = nsXPConnect::GetRuntime(); + XPCAutoLock al(rt->GetMapLock()); + + list = map->FindLink(wn->GetFlatJSObject()); + } + + if(!list) + return NS_OK; // No wrappers to update. + + AutoJSRequestWithNoCallContext req(aJSContext); + + Link* cur = list; + if(cur->obj && !PerformOp(aJSContext, aWay, cur->obj)) + return NS_ERROR_FAILURE; + + for(cur = (Link *)PR_NEXT_LINK(list); cur != list; + cur = (Link *)PR_NEXT_LINK(cur)) + { + if(!PerformOp(aJSContext, aWay, cur->obj)) + return NS_ERROR_FAILURE; + } + + return NS_OK; +} + /* void releaseJSContext (in JSContextPtr aJSContext, in PRBool noGC); */ NS_IMETHODIMP nsXPConnect::ReleaseJSContext(JSContext * aJSContext, PRBool noGC) diff --git a/js/src/xpconnect/src/xpcmaps.cpp b/js/src/xpconnect/src/xpcmaps.cpp index 7b96951c1af..6dc112c9ff1 100644 --- a/js/src/xpconnect/src/xpcmaps.cpp +++ b/js/src/xpconnect/src/xpcmaps.cpp @@ -652,6 +652,24 @@ XPCNativeWrapperMap::~XPCNativeWrapperMap() /***************************************************************************/ // implement WrappedNative2WrapperMap... +struct JSDHashTableOps +WrappedNative2WrapperMap::sOps = { nsnull }; + +// static +void +WrappedNative2WrapperMap::ClearLink(JSDHashTable* table, + JSDHashEntryHdr* entry) +{ + Entry* e = static_cast(entry); + e->key = nsnull; + if(e->value) + { + PR_REMOVE_LINK(e->value); + delete e->value; + e->value = nsnull; + } +} + // static WrappedNative2WrapperMap* WrappedNative2WrapperMap::newMap(int size) @@ -665,8 +683,13 @@ WrappedNative2WrapperMap::newMap(int size) WrappedNative2WrapperMap::WrappedNative2WrapperMap(int size) { - mTable = JS_NewDHashTable(JS_DHashGetStubOps(), nsnull, - sizeof(Entry), size); + if(!sOps.allocTable) + { + sOps = *JS_DHashGetStubOps(); + sOps.clearEntry = WrappedNative2WrapperMap::ClearLink; + } + + mTable = JS_NewDHashTable(&sOps, nsnull, sizeof(Entry), size); } WrappedNative2WrapperMap::~WrappedNative2WrapperMap() @@ -675,4 +698,71 @@ WrappedNative2WrapperMap::~WrappedNative2WrapperMap() JS_DHashTableDestroy(mTable); } +JSObject* +WrappedNative2WrapperMap::Add(WrappedNative2WrapperMap* head, + JSObject* wrappedObject, + JSObject* wrapper) +{ + NS_PRECONDITION(wrappedObject,"bad param"); + Entry* entry = (Entry*) + JS_DHashTableOperate(mTable, wrappedObject, JS_DHASH_ADD); + if(!entry) + return nsnull; + NS_ASSERTION(!entry->key || this == head, "dangling pointer?"); + entry->key = wrappedObject; + Link* l = new Link; + if(!l) + return nsnull; + PR_INIT_CLIST(l); + l->obj = wrapper; + + if(this != head) + { + Link* headLink = head->FindLink(wrappedObject); + if(!headLink) + { + Entry* dummy = (Entry*) + JS_DHashTableOperate(head->mTable, wrappedObject, JS_DHASH_ADD); + dummy->key = wrappedObject; + headLink = dummy->value = new Link; + if(!headLink) + { + Remove(wrappedObject); + return nsnull; + } + PR_INIT_CLIST(headLink); + headLink->obj = nsnull; + } + + PR_INSERT_BEFORE(l, headLink); + } + + entry->value = l; + return wrapper; +} + +PRBool +WrappedNative2WrapperMap::AddLink(JSObject* wrappedObject, Link* oldLink) +{ + Entry* entry = (Entry*) + JS_DHashTableOperate(mTable, wrappedObject, JS_DHASH_ADD); + if(!entry) + return PR_FALSE; + NS_ASSERTION(!entry->key, "Eh? What's happening?"); + entry->key = wrappedObject; + Link* newLink = entry->value = new Link; + if(!newLink) + { + Remove(wrappedObject); + return PR_FALSE; + } + + PR_INSERT_LINK(newLink, oldLink); + PR_REMOVE_AND_INIT_LINK(oldLink); + PR_INIT_CLIST(oldLink); + newLink->obj = oldLink->obj; + + return PR_TRUE; +} + /***************************************************************************/ diff --git a/js/src/xpconnect/src/xpcmaps.h b/js/src/xpconnect/src/xpcmaps.h index 135e3309037..9c08b8cc9bb 100644 --- a/js/src/xpconnect/src/xpcmaps.h +++ b/js/src/xpconnect/src/xpcmaps.h @@ -686,12 +686,21 @@ private: class WrappedNative2WrapperMap { + static struct JSDHashTableOps sOps; + + static void ClearLink(JSDHashTable* table, JSDHashEntryHdr* entry); + public: + struct Link : public PRCList + { + JSObject *obj; + }; + struct Entry : public JSDHashEntryHdr { // Note: key must be the flat JSObject for a wrapped native. JSObject* key; - JSObject* value; + Link* value; }; static WrappedNative2WrapperMap* newMap(int size); @@ -703,26 +712,29 @@ public: JS_DHashTableOperate(mTable, wrapper, JS_DHASH_LOOKUP); if(JS_DHASH_ENTRY_IS_FREE(entry)) return nsnull; - return entry->value; + return entry->value->obj; } // Note: If the entry already exists, then this will overwrite the // existing entry, returning the old value. - inline JSObject* Add(JSObject* wrapper, JSObject *obj) + JSObject* Add(WrappedNative2WrapperMap* head, + JSObject* wrappedObject, + JSObject* wrapper); + + // Function to find a link. + Link* FindLink(JSObject* wrappedObject) { - NS_PRECONDITION(wrapper,"bad param"); Entry* entry = (Entry*) - JS_DHashTableOperate(mTable, wrapper, JS_DHASH_ADD); - if(!entry) - return nsnull; - JSObject *old; - if(!entry->key) - entry->key = wrapper; - old = entry->value; - entry->value = obj; - return old; + JS_DHashTableOperate(mTable, wrappedObject, JS_DHASH_LOOKUP); + if(JS_DHASH_ENTRY_IS_BUSY(entry)) + return entry->value; + return nsnull; } + // "Internal" function to add an empty link without doing unnecessary + // work. + PRBool AddLink(JSObject* wrappedObject, Link* oldLink); + inline void Remove(JSObject* wrapper) { NS_PRECONDITION(wrapper,"bad param"); @@ -734,9 +746,11 @@ public: {return JS_DHashTableEnumerate(mTable, f, arg);} ~WrappedNative2WrapperMap(); + private: WrappedNative2WrapperMap(); // no implementation WrappedNative2WrapperMap(int size); + private: JSDHashTable *mTable; }; diff --git a/js/src/xpconnect/src/xpcprivate.h b/js/src/xpconnect/src/xpcprivate.h index df47e27bb3f..d3c67164bc7 100644 --- a/js/src/xpconnect/src/xpcprivate.h +++ b/js/src/xpconnect/src/xpcprivate.h @@ -91,6 +91,7 @@ #include "prlong.h" #include "prmem.h" #include "prenv.h" +#include "prclist.h" #include "nsString.h" #include "nsReadableUtils.h" #include "nsXPIDLString.h" diff --git a/js/src/xpconnect/src/xpcwrappednative.cpp b/js/src/xpconnect/src/xpcwrappednative.cpp index 5c87bcd1654..65b8a03bd55 100644 --- a/js/src/xpconnect/src/xpcwrappednative.cpp +++ b/js/src/xpconnect/src/xpcwrappednative.cpp @@ -1158,6 +1158,10 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, { // Oh, so now we need to move the wrapper to a different scope. + // First notify any XOWs. + nsXPConnect* xpc = nsXPConnect::GetXPConnect(); + xpc->UpdateXOWs(ccx, wrapper, nsIXPConnect::XPC_XOW_CLEARSCOPE); + AutoMarkingWrappedNativeProtoPtr oldProto(ccx); AutoMarkingWrappedNativeProtoPtr newProto(ccx); @@ -1179,6 +1183,12 @@ XPCWrappedNative::ReparentWrapperIfFound(XPCCallContext& ccx, } } + if(!XPC_XOW_WrapperMoved(ccx, wrapper, aNewScope)) + { + NS_RELEASE(wrapper); + return NS_ERROR_FAILURE; + } + Native2WrappedNativeMap* oldMap = aOldScope->GetWrappedNativeMap(); Native2WrappedNativeMap* newMap = aNewScope->GetWrappedNativeMap(); diff --git a/js/src/xpconnect/src/xpcwrappednativescope.cpp b/js/src/xpconnect/src/xpcwrappednativescope.cpp index e9938a5883e..24befddad12 100644 --- a/js/src/xpconnect/src/xpcwrappednativescope.cpp +++ b/js/src/xpconnect/src/xpcwrappednativescope.cpp @@ -270,6 +270,7 @@ XPCWrappedNativeScope::~XPCWrappedNativeScope() if(mWrapperMap) { + NS_ASSERTION(0 == mWrapperMap->Count(), "scope has non-empty map"); delete mWrapperMap; } diff --git a/js/src/xpconnect/tests/mochitest/Makefile.in b/js/src/xpconnect/tests/mochitest/Makefile.in index 356e7ca169c..738580e1cff 100644 --- a/js/src/xpconnect/tests/mochitest/Makefile.in +++ b/js/src/xpconnect/tests/mochitest/Makefile.in @@ -45,6 +45,7 @@ include $(DEPTH)/config/autoconf.mk include $(topsrcdir)/config/rules.mk _TEST_FILES = test_bug390488.html \ + test_bug393269.html \ test_wrappers.html \ $(NULL) diff --git a/js/src/xpconnect/tests/mochitest/test_bug393269.html b/js/src/xpconnect/tests/mochitest/test_bug393269.html new file mode 100644 index 00000000000..48ba0c0173b --- /dev/null +++ b/js/src/xpconnect/tests/mochitest/test_bug393269.html @@ -0,0 +1,46 @@ + + + + + Test for Bug 393269 + + + + + +Mozilla Bug 393269 + +
+
+
+ + +