diff --git a/docshell/test/chrome/chrome.ini b/docshell/test/chrome/chrome.ini index ce5e44c72cb2..6a7cd66c7109 100644 --- a/docshell/test/chrome/chrome.ini +++ b/docshell/test/chrome/chrome.ini @@ -84,6 +84,11 @@ skip-if = true # Bug 1026815,Bug 1546159 [test_bug89419.xhtml] [test_bug909218.html] [test_bug92598.xhtml] +[test_open_and_immediately_close_opener.html] +# This bug only manifests in the non-e10s window open codepath. The test +# should be updated to make sure it still opens a new window in the parent +# process if and when we start running chrome mochitests with e10s enabled. +skip-if = e10s [test_mozFrameType.xhtml] [test_viewsource_forbidden_in_iframe.xhtml] skip-if = true # bug 1019315 diff --git a/docshell/test/chrome/test_open_and_immediately_close_opener.html b/docshell/test/chrome/test_open_and_immediately_close_opener.html new file mode 100644 index 000000000000..bb5f6f054df1 --- /dev/null +++ b/docshell/test/chrome/test_open_and_immediately_close_opener.html @@ -0,0 +1,54 @@ + + + + Test for Bug 1702678 + + + + + +Mozilla Bug 1702678 + + + + + + diff --git a/dom/base/nsFrameLoader.cpp b/dom/base/nsFrameLoader.cpp index 7202ca16518a..bbb1a9e01a67 100644 --- a/dom/base/nsFrameLoader.cpp +++ b/dom/base/nsFrameLoader.cpp @@ -288,8 +288,23 @@ static already_AddRefed CreateBrowsingContext( RefPtr opener; if (aOpenWindowInfo && !aOpenWindowInfo->GetForceNoOpener()) { opener = aOpenWindowInfo->GetParent(); - // Must create BrowsingContext with opener in-process. - MOZ_ASSERT_IF(opener, opener->IsInProcess()); + if (opener) { + // Must create BrowsingContext with opener in-process. + MOZ_ASSERT(opener->IsInProcess()); + + // This can only happen when the opener was closed from a nested event + // loop in the window provider code, and only when the open was triggered + // by a non-e10s tab, and the new tab is being opened in a new browser + // window. Since it is a corner case among corner cases, and the opener + // window will appear to be null to consumers after it is discarded + // anyway, just drop the opener entirely. + if (opener->IsDiscarded()) { + NS_WARNING( + "Opener was closed from a nested event loop in the parent process. " + "Please fix this."); + opener = nullptr; + } + } } RefPtr parentInner = diff --git a/toolkit/components/windowwatcher/nsWindowWatcher.cpp b/toolkit/components/windowwatcher/nsWindowWatcher.cpp index 027f269e5e54..61ab895bfb89 100644 --- a/toolkit/components/windowwatcher/nsWindowWatcher.cpp +++ b/toolkit/components/windowwatcher/nsWindowWatcher.cpp @@ -986,8 +986,18 @@ nsresult nsWindowWatcher::OpenWindowInternal( // when its BrowsingContext was created, in order to ensure that the context // is loaded within the correct BrowsingContextGroup. if (windowIsNew && newBC->IsContent()) { - MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id()); - MOZ_RELEASE_ASSERT(!!parentBC == newBC->HadOriginalOpener()); + if (parentBC->IsDiscarded()) { + // If the parent BC was discarded in a nested event loop before we got + // to this point, we can't set it as the opener. Ideally we would still + // set `HadOriginalOpener()` in that case, but that's somewhat + // nontrivial, and not worth the effort given the nature of the corner + // case (see comment in `nsFrameLoader::CreateBrowsingContext`. + MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id() || + newBC->GetOpenerId() == 0); + } else { + MOZ_RELEASE_ASSERT(newBC->GetOpenerId() == parentBC->Id()); + MOZ_RELEASE_ASSERT(newBC->HadOriginalOpener()); + } } else { // Update the opener for an existing or chrome BC. newBC->SetOpener(parentBC);