Bug 1339722 - Check for mDoc after DispatchChromeEvent. r=smaug, a=lizzard
authorSamael Wang <freesamael@gmail.com>
Mon, 27 Feb 2017 18:03:23 +0800
changeset 378957 e8da840aef369d9e313f16a58e225dd9a9f01ed5
parent 378956 f4c59968a6eaf400caafbb890d8cd8bb37ccb178
child 378958 ed77e7b7d76e828eaf5d99a0b15691d2b9226638
push id1419
push userjlund@mozilla.com
push dateMon, 10 Apr 2017 20:44:07 +0000
treeherdermozilla-release@5e6801b73ef6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, lizzard
bugs1339722
milestone53.0
Bug 1339722 - Check for mDoc after DispatchChromeEvent. r=smaug, a=lizzard
dom/base/nsGlobalWindow.cpp
dom/base/test/chrome/chrome.ini
dom/base/test/chrome/test_bug1339722.html
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -2996,17 +2996,21 @@ nsGlobalWindow::DispatchDOMWindowCreated
 
   // Fire DOMWindowCreated at chrome event listeners
   nsContentUtils::DispatchChromeEvent(mDoc, mDoc, NS_LITERAL_STRING("DOMWindowCreated"),
                                       true /* bubbles */,
                                       false /* not cancellable */);
 
   nsCOMPtr<nsIObserverService> observerService =
     mozilla::services::GetObserverService();
-  if (observerService) {
+
+  // The event dispatching could possibly cause docshell destory, and
+  // consequently cause mDoc to be set to nullptr by DropOuterWindowDocs(),
+  // so check it again here.
+  if (observerService && mDoc) {
     nsAutoString origin;
     nsIPrincipal* principal = mDoc->NodePrincipal();
     nsContentUtils::GetUTFOrigin(principal, origin);
     observerService->
       NotifyObservers(static_cast<nsIDOMWindow*>(this),
                       nsContentUtils::IsSystemPrincipal(principal) ?
                         "chrome-document-global-created" :
                         "content-document-global-created",
--- a/dom/base/test/chrome/chrome.ini
+++ b/dom/base/test/chrome/chrome.ini
@@ -68,8 +68,9 @@ support-files = ../file_bug357450.js
 [test_fileconstructor.xul]
 [test_fileconstructor_tempfile.xul]
 [test_nsITextInputProcessor.xul]
 [test_range_getClientRectsAndTexts.html]
 [test_title.xul]
 [test_windowroot.xul]
 [test_swapFrameLoaders.xul]
 [test_groupedSHistory.xul]
+[test_bug1339722.html]
new file mode 100644
--- /dev/null
+++ b/dom/base/test/chrome/test_bug1339722.html
@@ -0,0 +1,67 @@
+<!DOCTYPE HTML>
+<html>
+<!--
+https://bugzilla.mozilla.org/show_bug.cgi?id=1339722
+-->
+<head>
+  <meta charset="utf-8">
+  <title>Test for Bug 1339722</title>
+  <script type="application/javascript" src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script>
+  <link rel="stylesheet" type="text/css" href="chrome://global/skin"/>
+  <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"/>
+  <script type="application/javascript">
+
+  /**
+   * Test for Bug 1339722
+   * 1. Wait for "http-on-useragent-request" for the iframe load.
+   * 2. In the observer, access it's window proxy to trigger DOMWindowCreated.
+   * 3. In the event handler, delete the iframe so that the frameloader would be
+   *    destoryed in the middle of ReallyStartLoading.
+   * 4. Verify that it doesn't crash.
+  **/
+
+  const {interfaces: Ci, utils: Cu} = Components;
+  Cu.import("resource://gre/modules/Services.jsm");
+
+  const TOPIC = 'http-on-useragent-request';
+  Services.obs.addObserver({
+    observe(subject, topic, data) {
+      info('Got ' + topic);
+      Services.obs.removeObserver(this, TOPIC);
+
+      // Query window proxy so it triggers DOMWindowCreated.
+      let channel = subject.QueryInterface(Ci.nsIHttpChannel);
+      let win = channel.notificationCallbacks.getInterface(Ci.mozIDOMWindowProxy);
+    }
+  }, TOPIC, false);
+
+  let docShell = SpecialPowers.wrap(window)
+                              .QueryInterface(Ci.nsIInterfaceRequestor)
+                              .getInterface(Ci.nsIDocShell);
+  docShell.chromeEventHandler.addEventListener('DOMWindowCreated', function handler(e) {
+    docShell.chromeEventHandler.removeEventListener('DOMWindowCreated', handler);
+    let iframe = document.getElementById('testFrame');
+    is(e.target, iframe.contentDocument, 'verify event target');
+
+    // Remove the iframe to cause frameloader destroy.
+    iframe.remove();
+    setTimeout($ => {
+      ok(!document.getElementById('testFrame'), 'verify iframe removed');
+      SimpleTest.finish();
+    }, 0);
+  });
+
+  SimpleTest.waitForExplicitFinish();
+  </script>
+</head>
+<body>
+<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1339722">Mozilla Bug 1339722</a>
+<p id="display"></p>
+<div id="content" style="display: none"></div>
+<pre id="test">
+  <div id="frameContainer">
+    <iframe id="testFrame" src="http://www.example.com"></iframe>
+  </div>
+</pre>
+</body>
+</html>