Bug 1562208: Don't assume that a child DocAccessibleParent is for a different process to its parent because there is a BrowserBridgeParent. r=yzen

Previously, DocAccessibleParent::AddChildDoc used the presence of a BrowserBridgeParent to determine whether the child document was in a different process to the parent document.
While this is normally the case, there can be a point while the embedded document is loading where there is a temporary document in the same (embedder) process.
In this case, we tried to get the COM proxy for the child document.
For a child document in the same process, this isn't available yet, so this caused infinite recursion (stack overflow) in ProxyAccessible::GetCOMInterface.

Instead of using the presence of BrowserBridgeParent, first check whether the child document is at the top level of its content process.
If it isn't, the document is in the same process as its parent.

Also, add a DIAGNOSTIC_ASSERT to ProxyAccessible::GetCOMInterface which will fire if no COM proxy or MSAA child id has been set.
Previously, we just recursed infinitely and overflowed the stack in this case, which is painful to debug.

Differential Revision: https://phabricator.services.mozilla.com/D37344

--HG--
extra : moz-landing-system : lando
This commit is contained in:
James Teh 2019-07-09 00:56:56 +00:00
Родитель 5b5df637b1
Коммит 43f890d3a4
2 изменённых файлов: 31 добавлений и 28 удалений

Просмотреть файл

@ -537,38 +537,40 @@ ipc::IPCResult DocAccessibleParent::AddChildDoc(DocAccessibleParent* aChildDoc,
}
#if defined(XP_WIN)
auto embeddedBrowser = static_cast<dom::BrowserParent*>(aChildDoc->Manager());
dom::BrowserBridgeParent* bridge = embeddedBrowser->GetBrowserBridgeParent();
if (bridge) {
if (aChildDoc->IsTopLevelInContentProcess()) {
// aChildDoc is an embedded document in a different content process to
// this document.
// Send a COM proxy for the embedded document to the embedder process
// hosting the iframe. This will be returned as the child of the
// embedder OuterDocAccessible.
RefPtr<IDispatch> docAcc;
aChildDoc->GetCOMInterface((void**)getter_AddRefs(docAcc));
RefPtr<IDispatch> docWrapped(
mscom::PassthruProxy::Wrap<IDispatch>(WrapNotNull(docAcc)));
IDispatchHolder::COMPtrType docPtr(
mscom::ToProxyUniquePtr(std::move(docWrapped)));
IDispatchHolder docHolder(std::move(docPtr));
if (bridge->SendSetEmbeddedDocAccessibleCOMProxy(docHolder)) {
auto embeddedBrowser = static_cast<dom::BrowserParent*>(aChildDoc->Manager());
dom::BrowserBridgeParent* bridge = embeddedBrowser->GetBrowserBridgeParent();
if (bridge) {
// Send a COM proxy for the embedded document to the embedder process
// hosting the iframe. This will be returned as the child of the
// embedder OuterDocAccessible.
RefPtr<IDispatch> docAcc;
aChildDoc->GetCOMInterface((void**)getter_AddRefs(docAcc));
RefPtr<IDispatch> docWrapped(
mscom::PassthruProxy::Wrap<IDispatch>(WrapNotNull(docAcc)));
IDispatchHolder::COMPtrType docPtr(
mscom::ToProxyUniquePtr(std::move(docWrapped)));
IDispatchHolder docHolder(std::move(docPtr));
if (bridge->SendSetEmbeddedDocAccessibleCOMProxy(docHolder)) {
# if defined(MOZ_SANDBOX)
mDocProxyStream = docHolder.GetPreservedStream();
mDocProxyStream = docHolder.GetPreservedStream();
# endif // defined(MOZ_SANDBOX)
}
// Send a COM proxy for the embedder OuterDocAccessible to the embedded
// document process. This will be returned as the parent of the
// embedded document.
aChildDoc->SendParentCOMProxy(WrapperFor(outerDoc));
if (nsWinUtils::IsWindowEmulationStarted()) {
// The embedded document should use the same emulated window handle as
// its embedder. It will return the embedder document (not a window
// accessible) as the parent accessible, so we pass a null accessible
// when sending the window to the embedded document.
aChildDoc->SetEmulatedWindowHandle(mEmulatedWindowHandle);
Unused << aChildDoc->SendEmulatedWindow(
reinterpret_cast<uintptr_t>(mEmulatedWindowHandle), nullptr);
}
// Send a COM proxy for the embedder OuterDocAccessible to the embedded
// document process. This will be returned as the parent of the
// embedded document.
aChildDoc->SendParentCOMProxy(WrapperFor(outerDoc));
if (nsWinUtils::IsWindowEmulationStarted()) {
// The embedded document should use the same emulated window handle as
// its embedder. It will return the embedder document (not a window
// accessible) as the parent accessible, so we pass a null accessible
// when sending the window to the embedded document.
aChildDoc->SetEmulatedWindowHandle(mEmulatedWindowHandle);
Unused << aChildDoc->SendEmulatedWindow(
reinterpret_cast<uintptr_t>(mEmulatedWindowHandle), nullptr);
}
}
}
#endif // defined(XP_WIN)

Просмотреть файл

@ -42,6 +42,7 @@ bool ProxyAccessible::GetCOMInterface(void** aOutAccessible) const {
// overflow the stack.
VARIANT realId = {{{VT_I4}}};
realId.ulVal = wrap->GetExistingID();
MOZ_DIAGNOSTIC_ASSERT(realId.ulVal != CHILDID_SELF);
thisPtr->mCOMProxy = wrap->GetIAccessibleFor(realId, &isDefunct);
}