Bug 586157 - Deal with setting __proto__ on outer windows. r=jst

This commit is contained in:
Blake Kaplan 2010-08-13 17:05:18 -07:00
parent b250974915
commit d8bc476488
3 changed files with 92 additions and 51 deletions

View File

@ -1512,7 +1512,8 @@ public:
WindowStateHolder(nsGlobalWindow *aWindow,
nsIXPConnectJSObjectHolder *aHolder,
nsNavigator *aNavigator,
nsIXPConnectJSObjectHolder *aOuterProto);
nsIXPConnectJSObjectHolder *aOuterProto,
nsIXPConnectJSObjectHolder *aOuterRealProto);
nsGlobalWindow* GetInnerWindow() { return mInnerWindow; }
nsIXPConnectJSObjectHolder *GetInnerWindowHolder()
@ -1520,6 +1521,7 @@ public:
nsNavigator* GetNavigator() { return mNavigator; }
nsIXPConnectJSObjectHolder* GetOuterProto() { return mOuterProto; }
nsIXPConnectJSObjectHolder* GetOuterRealProto() { return mOuterRealProto; }
void DidRestoreWindow()
{
@ -1528,6 +1530,7 @@ public:
mInnerWindowHolder = nsnull;
mNavigator = nsnull;
mOuterProto = nsnull;
mOuterRealProto = nsnull;
}
protected:
@ -1539,6 +1542,7 @@ protected:
nsCOMPtr<nsIXPConnectJSObjectHolder> mInnerWindowHolder;
nsRefPtr<nsNavigator> mNavigator;
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterProto;
nsCOMPtr<nsIXPConnectJSObjectHolder> mOuterRealProto;
};
NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
@ -1546,10 +1550,12 @@ NS_DEFINE_STATIC_IID_ACCESSOR(WindowStateHolder, WINDOWSTATEHOLDER_IID)
WindowStateHolder::WindowStateHolder(nsGlobalWindow *aWindow,
nsIXPConnectJSObjectHolder *aHolder,
nsNavigator *aNavigator,
nsIXPConnectJSObjectHolder *aOuterProto)
nsIXPConnectJSObjectHolder *aOuterProto,
nsIXPConnectJSObjectHolder *aOuterRealProto)
: mInnerWindow(aWindow),
mNavigator(aNavigator),
mOuterProto(aOuterProto)
mOuterProto(aOuterProto),
mOuterRealProto(aOuterRealProto)
{
NS_PRECONDITION(aWindow, "null window");
NS_PRECONDITION(aWindow->IsInnerWindow(), "Saving an outer window");
@ -1722,12 +1728,20 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
JSAutoRequest ar(cx);
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
NS_ASSERTION(!aState || wsh, "What kind of weird state are you giving me here?");
// Make sure to clear scope on the outer window *before* we
// initialize the new inner window. If we don't, things
// (Object.prototype etc) could leak from the old outer to the new
// inner scope.
mContext->ClearScope(mJSObject, PR_FALSE);
// This code should not be called during shutdown any more (now that
// we don't ever call SetNewDocument(nsnull), so no need to null
// check xpc here.
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
if (reUseInnerWindow) {
// We're reusing the current inner window.
NS_ASSERTION(!currentInner->IsFrozen(),
@ -1739,9 +1753,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
}
} else {
if (aState) {
nsCOMPtr<WindowStateHolder> wsh = do_QueryInterface(aState);
NS_ASSERTION(wsh, "What kind of weird state are you giving me here?");
newInnerWindow = wsh->GetInnerWindow();
mInnerWindowHolder = wsh->GetInnerWindowHolder();
@ -1875,12 +1886,37 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
mJSObject = (JSObject *)mContext->GetNativeGlobal();
} else {
// XXX New global object and brain transplant!
nsIXPConnect *xpc = nsContentUtils::XPConnect();
rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
// Restore our object's prototype to its original value so we're sure to
// update it under ReparentWrappedNativeIfFound.
JSObject *proto;
wrapper->GetJSObjectPrototype(&proto);
if (!JS_SetPrototype(cx, mJSObject, proto)) {
NS_ERROR("Can't set prototype");
return NS_ERROR_UNEXPECTED;
}
nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
xpc->ReparentWrappedNativeIfFound(cx, currentInner->mJSObject,
newInnerWindow->mJSObject,
ToSupports(this),
getter_AddRefs(holder));
if (aState) {
if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
holder->GetJSObject(&proto);
} else {
proto = nsnull;
}
if (!JS_SetPrototype(cx, mJSObject, proto)) {
NS_ERROR("can't set prototype");
return NS_ERROR_FAILURE;
}
}
}
}
@ -1934,11 +1970,6 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
html_doc);
}
// This code should not be called during shutdown any more (now that
// we don't ever call SetNewDocument(nsnull), so no need to null
// check xpc here.
nsIXPConnect *xpc = nsContentUtils::XPConnect();
if (aDocument) {
aDocument->SetScriptGlobalObject(newInnerWindow);
}
@ -2004,10 +2035,11 @@ nsGlobalWindow::SetNewDocument(nsIDocument* aDocument,
mContext->GC();
mContext->DidInitializeContext();
nsCOMPtr<nsIXPConnectWrappedNative> wrapper;
rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
if (!wrapper) {
rv = xpc->GetWrappedNativeOfJSObject(cx, mJSObject,
getter_AddRefs(wrapper));
NS_ENSURE_SUCCESS(rv, rv);
}
rv = xpc->UpdateXOWs((JSContext *)GetContextInternal()->GetNativeContext(),
wrapper, nsIXPConnect::XPC_XOW_NAVIGATED);
@ -9051,21 +9083,39 @@ nsGlobalWindow::SaveWindowState(nsISupports **aState)
// to the page.
inner->Freeze();
// Remember the outer window's XPConnect prototype.
// Remember the outer window's prototype.
JSContext *cx = (JSContext *)mContext->GetNativeContext();
JSAutoRequest req(cx);
nsIXPConnect *xpc = nsContentUtils::XPConnect();
nsCOMPtr<nsIClassInfo> ci =
do_QueryInterface((nsIScriptGlobalObject *)this);
nsCOMPtr<nsIXPConnectJSObjectHolder> proto;
nsresult rv = nsContentUtils::XPConnect()->
GetWrappedNativePrototype((JSContext *)mContext->GetNativeContext(),
mJSObject, ci, getter_AddRefs(proto));
nsresult rv = xpc->GetWrappedNativePrototype(cx, mJSObject, ci,
getter_AddRefs(proto));
NS_ENSURE_SUCCESS(rv, rv);
JSObject *realProto = JS_GetPrototype(cx, mJSObject);
nsCOMPtr<nsIXPConnectJSObjectHolder> realProtoHolder;
if (realProto) {
rv = xpc->HoldObject(cx, realProto, getter_AddRefs(realProtoHolder));
NS_ENSURE_SUCCESS(rv, rv);
}
nsCOMPtr<nsISupports> state = new WindowStateHolder(inner,
mInnerWindowHolder,
mNavigator,
proto);
proto,
realProtoHolder);
NS_ENSURE_TRUE(state, NS_ERROR_OUT_OF_MEMORY);
JSObject *wnProto;
proto->GetJSObject(&wnProto);
if (!JS_SetPrototype(cx, mJSObject, wnProto)) {
return NS_ERROR_FAILURE;
}
#ifdef DEBUG_PAGE_CACHE
printf("saving window state, state = %p\n", (void*)state);
#endif

View File

@ -399,7 +399,7 @@ interface nsIXPCFunctionThisTranslator : nsISupports
{ 0xbd, 0xd6, 0x0, 0x0, 0x64, 0x65, 0x73, 0x74 } }
%}
[uuid(4abf8614-2b0c-495f-8c67-97115470b53c)]
[uuid(7a3c8687-6f52-47d5-9b8e-2ed8bf86c415)]
interface nsIXPConnect : nsISupports
{
%{ C++
@ -413,16 +413,6 @@ interface nsIXPConnect : nsISupports
initClasses(in JSContextPtr aJSContext,
in JSObjectPtr aGlobalJSObj);
/**
* Like initClasses, but only does some of the initialization on the
* existing global. In particular this function assumes that the outer
* window has already been connected to an inner window, so
* re-initializing things like XPCNativeWrapper is useless.
*/
void
initClassesForOuterObject(in JSContextPtr aJSContext,
in JSObjectPtr aGlobalJSObj);
/**
* Creates a new global object using the given aCOMObj as the global
* object. The object will be set up according to the flags (defined
@ -895,4 +885,11 @@ interface nsIXPConnect : nsISupports
[notxpcom] void getNativeWrapperGetPropertyOp(out JSPropertyOp getProperty);
[notxpcom] void getXrayWrapperPropertyHolderGetPropertyOp(out JSPropertyOp getProperty);
/**
* Creates a JS object holder around aObject that will hold the object
* alive for as long as the holder stays alive.
*/
nsIXPConnectJSObjectHolder holdObject(in JSContextPtr aJSContext,
in JSObjectPtr aObject);
};

View File

@ -1042,25 +1042,6 @@ nsXPConnect::InitClasses(JSContext * aJSContext, JSObject * aGlobalJSObj)
return NS_OK;
}
/* void initClassesForOuterObject (in JSContextPtr aJSContext, in JSObjectPtr aGlobalJSObj); */
NS_IMETHODIMP nsXPConnect::InitClassesForOuterObject(JSContext * aJSContext, JSObject * aGlobalJSObj)
{
// Nest frame chain save/restore in request created by XPCCallContext.
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
if(!ccx.IsValid())
return UnexpectedFailure(NS_ERROR_FAILURE);
SaveFrame sf(aJSContext);
XPCWrappedNativeScope* scope =
XPCWrappedNativeScope::GetNewOrUsed(ccx, aGlobalJSObj);
if(!scope)
return UnexpectedFailure(NS_ERROR_FAILURE);
scope->RemoveWrappedNativeProtos();
return NS_OK;
}
static JSBool
TempGlobalResolve(JSContext *aJSContext, JSObject *obj, jsid id)
{
@ -2786,6 +2767,19 @@ nsXPConnect::GetNativeWrapperGetPropertyOp(JSPropertyOp *getPropertyPtr)
*getPropertyPtr = XPCNativeWrapper::GetJSClass(true)->getProperty;
}
NS_IMETHODIMP
nsXPConnect::HoldObject(JSContext *aJSContext, JSObject *aObject,
nsIXPConnectJSObjectHolder **aHolder)
{
XPCCallContext ccx(NATIVE_CALLER, aJSContext);
XPCJSObjectHolder* objHolder = XPCJSObjectHolder::newHolder(ccx, aObject);
if(!objHolder)
return NS_ERROR_OUT_OF_MEMORY;
NS_ADDREF(*aHolder = objHolder);
return NS_OK;
}
/* These are here to be callable from a debugger */
JS_BEGIN_EXTERN_C
JS_EXPORT_API(void) DumpJSStack()