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);