Bug 984467 - Remove current inner fallback in CallerInnerWindow. r=bz, a=lsblakk
authorBobby Holley <bobbyholley@gmail.com>
Thu, 13 Nov 2014 11:13:37 -0800
changeset 233907 9d115d5d0a374d79d113649ef420bef42dac1670
parent 233906 5531b615a4850fba67342aa6768f6bc99460cbba
child 233908 dd2f144cdf445b630ed16c5debf5034f7435cd80
push id4187
push userbhearsum@mozilla.com
push dateFri, 28 Nov 2014 15:29:12 +0000
treeherdermozilla-beta@f23cc6a30c11 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbz, lsblakk
bugs984467
milestone35.0a2
Bug 984467 - Remove current inner fallback in CallerInnerWindow. r=bz, a=lsblakk
dom/base/nsGlobalWindow.cpp
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -7743,44 +7743,32 @@ nsGlobalWindow::CallerInnerWindow()
   NS_ENSURE_TRUE(scope, nullptr);
 
   // When Jetpack runs content scripts inside a sandbox, it uses
   // sandboxPrototype to make them appear as though they're running in the
   // scope of the page. So when a content script invokes postMessage, it expects
   // the |source| of the received message to be the window set as the
   // sandboxPrototype. This used to work incidentally for unrelated reasons, but
   // now we need to do some special handling to support it.
-  {
+  if (xpc::IsSandbox(scope)) {
     JSAutoCompartment ac(cx, scope);
     JS::Rooted<JSObject*> scopeProto(cx);
     bool ok = JS_GetPrototype(cx, scope, &scopeProto);
     NS_ENSURE_TRUE(ok, nullptr);
     if (scopeProto && xpc::IsSandboxPrototypeProxy(scopeProto) &&
         (scopeProto = js::CheckedUnwrap(scopeProto, /* stopAtOuter = */ false)))
     {
-      scope = scopeProto;
-    }
-  }
-  JSAutoCompartment ac(cx, scope);
-
-  // We don't use xpc::WindowOrNull here because we want to be able to tell
-  // apart the cases of "scope is not an nsISupports at all" and "scope is an
-  // nsISupports that's not a window". It's not clear whether that's desirable,
-  // see bug 984467.
-  nsISupports* native =
-    nsContentUtils::XPConnect()->GetNativeOfWrapper(cx, scope);
-  if (!native)
-    return nullptr;
-
-  // The calling window must be holding a reference, so we can just return a
-  // raw pointer here and let the QI's addref be balanced by the nsCOMPtr
-  // destructor's release.
-  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(native);
-  if (!win)
-    return GetCurrentInnerWindowInternal();
+      global = xpc::NativeGlobal(scopeProto);
+      NS_ENSURE_TRUE(global, nullptr);
+    }
+  }
+
+  // The calling window must be holding a reference, so we can return a weak
+  // pointer.
+  nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(global);
   return static_cast<nsGlobalWindow*>(win.get());
 }
 
 /**
  * Class used to represent events generated by calls to Window.postMessage,
  * which asynchronously creates and dispatches events.
  */
 class PostMessageEvent : public nsRunnable
@@ -11886,16 +11874,19 @@ nsGlobalWindow::InnerForSetTimeoutOrInte
     // This needs to forward to the inner window, but since the current
     // inner may not be the inner in the calling scope, we need to treat
     // this specially here as we don't want timeouts registered in a
     // dying inner window to get registered and run on the current inner
     // window. To get this right, we need to forward this call to the
     // inner window that's calling window.setTimeout().
 
     forwardTo = CallerInnerWindow();
+    if (!forwardTo && nsContentUtils::IsCallerChrome()) {
+      forwardTo = currentInner;
+    }
     if (!forwardTo) {
       aError.Throw(NS_ERROR_NOT_AVAILABLE);
       return nullptr;
     }
 
     // If the caller and the callee share the same outer window, forward to the
     // caller inner. Else, we forward to the current inner (e.g. someone is
     // calling setTimeout() on a reference to some other window).
@@ -12104,24 +12095,25 @@ nsGlobalWindow::SetTimeoutOrInterval(boo
   // inner may not be the inner in the calling scope, we need to treat
   // this specially here as we don't want timeouts registered in a
   // dying inner window to get registered and run on the current inner
   // window. To get this right, we need to forward this call to the
   // inner window that's calling window.setTimeout().
 
   if (IsOuterWindow()) {
     nsGlobalWindow* callerInner = CallerInnerWindow();
-    NS_ENSURE_TRUE(callerInner, NS_ERROR_NOT_AVAILABLE);
+    NS_ENSURE_TRUE(callerInner || nsContentUtils::IsCallerChrome(), NS_ERROR_NOT_AVAILABLE);
 
     // If the caller and the callee share the same outer window,
     // forward to the callee inner. Else, we forward to the current
     // inner (e.g. someone is calling setTimeout() on a reference to
     // some other window).
 
-    if (callerInner->GetOuterWindow() == this &&
+    if (callerInner &&
+        callerInner->GetOuterWindow() == this &&
         callerInner->IsInnerWindow()) {
       return callerInner->SetTimeoutOrInterval(aIsInterval, aReturn);
     }
 
     FORWARD_TO_INNER(SetTimeoutOrInterval, (aIsInterval, aReturn),
                      NS_ERROR_NOT_INITIALIZED);
   }