Bug 1000175. Make sure error events on window only fire if the active document has not changed from when the exception was thrown. r=smaug
authorBoris Zbarsky <bzbarsky@mit.edu>
Tue, 20 May 2014 16:07:17 -0400
changeset 184015 302499f09610576d279c22d0df844012d61bd6b7
parent 184014 e50261fb680076804d4fd5fb733d5a8179a983c5
child 184016 55d1924160c9fcb408935a5ecc2672abf7b60535
push id26810
push usercbook@mozilla.com
push dateWed, 21 May 2014 11:46:36 +0000
treeherdermozilla-central@50fb8c4db2fd [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug
bugs1000175
milestone32.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1000175. Make sure error events on window only fire if the active document has not changed from when the exception was thrown. r=smaug
dom/base/nsJSEnvironment.cpp
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -381,20 +381,18 @@ AsyncErrorReporter::AsyncErrorReporter(J
   if (mErrorMsg.IsEmpty() && aFallbackMessage) {
     mErrorMsg.AssignWithConversion(aFallbackMessage);
   }
 
   mCategory = aIsChromeError ? NS_LITERAL_CSTRING("chrome javascript") :
                                NS_LITERAL_CSTRING("content javascript");
 
   mInnerWindowID = 0;
-  if (aWindow && aWindow->IsOuterWindow()) {
-    aWindow = aWindow->GetCurrentInnerWindow();
-  }
   if (aWindow) {
+    MOZ_ASSERT(aWindow->IsInnerWindow());
     mInnerWindowID = aWindow->WindowID();
   }
 }
 
 void
 AsyncErrorReporter::ReportError()
 {
   nsCOMPtr<nsIScriptError> errorObject =
@@ -422,59 +420,59 @@ AsyncErrorReporter::ReportError()
 }
 
 } // namespace dom
 } // namespace mozilla
 
 class ScriptErrorEvent : public AsyncErrorReporter
 {
 public:
-  ScriptErrorEvent(nsIScriptGlobalObject* aScriptGlobal,
-                   JSRuntime* aRuntime,
+  ScriptErrorEvent(JSRuntime* aRuntime,
                    JSErrorReport* aErrorReport,
                    const char* aFallbackMessage,
                    nsIPrincipal* aScriptOriginPrincipal,
                    nsIPrincipal* aGlobalPrincipal,
                    nsPIDOMWindow* aWindow,
                    JS::Handle<JS::Value> aError,
                    bool aDispatchEvent)
     // Pass an empty category, then compute ours
     : AsyncErrorReporter(aRuntime, aErrorReport, aFallbackMessage,
                          nsContentUtils::IsSystemPrincipal(aGlobalPrincipal),
                          aWindow)
-    , mScriptGlobal(aScriptGlobal)
     , mOriginPrincipal(aScriptOriginPrincipal)
     , mDispatchEvent(aDispatchEvent)
     , mError(aRuntime, aError)
+    , mWindow(aWindow)
   {
+    MOZ_ASSERT_IF(mWindow, mWindow->IsInnerWindow());
   }
 
   NS_IMETHOD Run()
   {
     nsEventStatus status = nsEventStatus_eIgnore;
-    // First, notify the DOM that we have a script error.
-    if (mDispatchEvent) {
-      nsCOMPtr<nsPIDOMWindow> win(do_QueryInterface(mScriptGlobal));
-      nsIDocShell* docShell = win ? win->GetDocShell() : nullptr;
+    // First, notify the DOM that we have a script error, but only if
+    // our window is still the current inner, if we're associated with a window.
+    if (mDispatchEvent && (!mWindow || mWindow->IsCurrentInnerWindow())) {
+      nsIDocShell* docShell = mWindow ? mWindow->GetDocShell() : nullptr;
       if (docShell &&
           !JSREPORT_IS_WARNING(mFlags) &&
           !sHandlingScriptError) {
         AutoRestore<bool> recursionGuard(sHandlingScriptError);
         sHandlingScriptError = true;
 
         nsRefPtr<nsPresContext> presContext;
         docShell->GetPresContext(getter_AddRefs(presContext));
 
         ThreadsafeAutoJSContext cx;
         RootedDictionary<ErrorEventInit> init(cx);
         init.mCancelable = true;
         init.mFilename = mFileName;
         init.mBubbles = true;
 
-        nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(win));
+        nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(mWindow));
         NS_ENSURE_STATE(sop);
         nsIPrincipal* p = sop->GetPrincipal();
         NS_ENSURE_STATE(p);
 
         bool sameOrigin = !mOriginPrincipal;
 
         if (p && !sameOrigin) {
           if (NS_FAILED(p->Subsumes(mOriginPrincipal, &sameOrigin))) {
@@ -490,37 +488,37 @@ public:
           init.mError = mError;
         } else {
           NS_WARNING("Not same origin error!");
           init.mMessage = xoriginMsg;
           init.mLineno = 0;
         }
 
         nsRefPtr<ErrorEvent> event =
-          ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(win.get()),
+          ErrorEvent::Constructor(static_cast<nsGlobalWindow*>(mWindow.get()),
                                   NS_LITERAL_STRING("error"), init);
         event->SetTrusted(true);
 
-        EventDispatcher::DispatchDOMEvent(win, nullptr, event, presContext,
+        EventDispatcher::DispatchDOMEvent(mWindow, nullptr, event, presContext,
                                           &status);
       }
     }
 
     if (status != nsEventStatus_eConsumeNoDefault) {
       AsyncErrorReporter::ReportError();
     }
 
     return NS_OK;
   }
 
 private:
-  nsCOMPtr<nsIScriptGlobalObject> mScriptGlobal;
   nsCOMPtr<nsIPrincipal>          mOriginPrincipal;
   bool                            mDispatchEvent;
   JS::PersistentRootedValue       mError;
+  nsCOMPtr<nsPIDOMWindow>         mWindow;
 
   static bool sHandlingScriptError;
 };
 
 bool ScriptErrorEvent::sHandlingScriptError = false;
 
 // NOTE: This function could be refactored to use the above.  The only reason
 // it has not been done is that the code below only fills the error event
@@ -568,23 +566,25 @@ NS_ScriptErrorReporter(JSContext *cx,
   ::JS_ClearPendingException(cx);
 
   if (context) {
     nsIScriptGlobalObject *globalObject = context->GetGlobalObject();
 
     if (globalObject) {
 
       nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(globalObject);
+      if (win) {
+        win = win->GetCurrentInnerWindow();
+      }
       nsCOMPtr<nsIScriptObjectPrincipal> scriptPrincipal =
         do_QueryInterface(globalObject);
       NS_ASSERTION(scriptPrincipal, "Global objects must implement "
                    "nsIScriptObjectPrincipal");
       nsContentUtils::AddScriptRunner(
-        new ScriptErrorEvent(globalObject,
-                             JS_GetRuntime(cx),
+        new ScriptErrorEvent(JS_GetRuntime(cx),
                              report,
                              message,
                              nsJSPrincipals::get(report->originPrincipals),
                              scriptPrincipal->GetPrincipal(),
                              win,
                              exception,
                              /* We do not try to report Out Of Memory via a dom
                               * event because the dom event handler would