Bug 640904 - Check for null window globals within PreCreate hooks and assert IsClosedOrClosing(). r=peterv,smaug
authorBobby Holley <bobbyholley@gmail.com>
Fri, 27 Apr 2012 10:38:14 +0200
changeset 94882 712bca8b8674493ac7fd29fa3c0b376514786745
parent 94881 eb4b76b2840f820f4b9549df4af6abe01fdd110b
child 94883 76447b588eea4fd7f1a5e74e13e482d2e1a7ea27
push idunknown
push userunknown
push dateunknown
reviewerspeterv, smaug
bugs640904
milestone15.0a1
Bug 640904 - Check for null window globals within PreCreate hooks and assert IsClosedOrClosing(). r=peterv,smaug
dom/base/nsDOMClassInfo.cpp
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -530,16 +530,18 @@ using mozilla::dom::indexedDB::IDBWrappe
 #ifdef MOZ_B2G_BT
 #include "BluetoothAdapter.h"
 #include "BluetoothDevice.h"
 #endif
 
 #include "DOMError.h"
 #include "DOMRequest.h"
 
+#include "mozilla/Likely.h"
+
 #undef None // something included above defines this preprocessor symbol, maybe Xlib headers
 #include "WebGLContext.h"
 
 using namespace mozilla;
 using namespace mozilla::dom;
 
 static NS_DEFINE_CID(kDOMSOF_CID, NS_DOM_SCRIPT_OBJECT_FACTORY_CID);
 
@@ -1963,16 +1965,33 @@ WrapNativeParent(JSContext *cx, JSObject
 
   jsval v;
   nsresult rv = WrapNative(cx, scope, native, nativeWrapperCache, false, &v);
   NS_ENSURE_SUCCESS(rv, rv);
   *parentObj = JSVAL_TO_OBJECT(v);
   return NS_OK;
 }
 
+// Helper to handle torn-down inner windows.
+static inline nsresult
+SetParentToWindow(nsGlobalWindow *win, JSObject **parent)
+{
+  MOZ_ASSERT(win);
+  MOZ_ASSERT(win->IsInnerWindow());
+  *parent = win->FastGetGlobalJSObject();
+
+  if (MOZ_UNLIKELY(!*parent)) {
+    // The only known case where this can happen is when the inner window has
+    // been torn down. See bug 691178 comment 11.
+    MOZ_ASSERT(win->IsClosedOrClosing());
+    return NS_ERROR_FAILURE;
+  }
+  return NS_OK;
+}
+
 // static
 
 nsISupports *
 nsDOMClassInfo::GetNative(nsIXPConnectWrappedNative *wrapper, JSObject *obj)
 {
   return wrapper ? wrapper->Native() : static_cast<nsISupports*>(js::GetObjectPrivate(obj));
 }
 
@@ -4624,18 +4643,19 @@ nsDOMClassInfo::PreCreate(nsISupports *n
 
   nsCOMPtr<nsPIDOMWindow> piwin = do_QueryWrapper(cx, globalObj);
 
   if (!piwin) {
     return NS_OK;
   }
 
   if (piwin->IsOuterWindow()) {
-    *parentObj = ((nsGlobalWindow *)piwin.get())->
-      GetCurrentInnerWindowInternal()->GetGlobalJSObject();
+    nsGlobalWindow *win = ((nsGlobalWindow *)piwin.get())->
+                            GetCurrentInnerWindowInternal();
+    return SetParentToWindow(win, parentObj);
   }
 
   return NS_OK;
 }
 
 NS_IMETHODIMP
 nsDOMClassInfo::Create(nsIXPConnectWrappedNative *wrapper,
                        JSContext *cx, JSObject *obj)
@@ -5160,30 +5180,25 @@ nsWindowSH::PreCreate(nsISupports *nativ
   // after the wrapper is found.
 
   nsCOMPtr<nsIScriptGlobalObject> sgo(do_QueryInterface(nativeObj));
   NS_ASSERTION(sgo, "nativeObj not a global object!");
 
   nsGlobalWindow *win = nsGlobalWindow::FromSupports(nativeObj);
   NS_ASSERTION(win->IsInnerWindow(), "Should be inner window.");
 
-  JSObject *winObj = win->FastGetGlobalJSObject();
-  if (!winObj) {
-
-    // See bug 691178 comment 11 for why this is necessary.
-    if (win->IsClosedOrClosing())
-      return NS_ERROR_FAILURE;
-
-    NS_ASSERTION(win->GetOuterWindowInternal()->IsCreatingInnerWindow(),
-                 "should have a JS object by this point");
+  // We sometimes get a disconnected window during file api test. :-(
+  if (!win->GetOuterWindowInternal())
+    return NS_ERROR_FAILURE;
+
+  // If we're bootstrapping, we don't have a JS object yet.
+  if (win->GetOuterWindowInternal()->IsCreatingInnerWindow())
     return NS_OK;
-  }
-
-  *parentObj = winObj;
-  return NS_OK;
+
+  return SetParentToWindow(win, parentObj);
 }
 
 // This JS class piggybacks on nsHTMLDocumentSH::ReleaseDocument()...
 
 static JSClass sGlobalScopePolluterClass = {
   "Global Scope Polluter",
   JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE,
   nsWindowSH::SecurityCheckOnAddDelProp,
@@ -6024,18 +6039,17 @@ nsDOMConstructor::PreCreate(JSContext *c
 {
   nsCOMPtr<nsPIDOMWindow> owner(do_QueryReferent(mWeakOwner));
   if (!owner) {
     // Can't do anything.
     return NS_OK;
   }
 
   nsGlobalWindow *win = static_cast<nsGlobalWindow *>(owner.get());
-  *parentObj = win->FastGetGlobalJSObject();
-  return NS_OK;
+  return SetParentToWindow(win, parentObj);
 }
 
 nsresult
 nsDOMConstructor::Construct(nsIXPConnectWrappedNative *wrapper, JSContext * cx,
                             JSObject * obj, PRUint32 argc, jsval * argv,
                             jsval * vp, bool *_retval)
 {
   JSObject* class_obj = JSVAL_TO_OBJECT(argv[-2]);
@@ -7475,17 +7489,17 @@ nsLocationSH::PreCreate(nsISupports *nat
   nsCOMPtr<nsIScriptGlobalObject> sgo = do_GetInterface(ds);
   if (!sgo) {
     NS_WARNING("Refusing to create a location in the wrong scope because the "
                "docshell is being destroyed");
     return NS_ERROR_UNEXPECTED;
   }
 
   *parentObj = sgo->GetGlobalJSObject();
-  return NS_OK;
+  return *parentObj ? NS_OK : NS_ERROR_FAILURE;
 }
 
 // DOM Navigator helper
 
 NS_IMETHODIMP
 nsNavigatorSH::NewResolve(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                           JSObject *obj, jsid id, PRUint32 flags,
                           JSObject **objp, bool *_retval)
@@ -7574,24 +7588,17 @@ nsNavigatorSH::PreCreate(nsISupports *na
 
   Navigator *nav = static_cast<Navigator*>(safeNav.get());
   nsGlobalWindow *win = static_cast<nsGlobalWindow*>(nav->GetWindow());
   if (!win) {
     NS_WARNING("Refusing to create a navigator in the wrong scope");
 
     return NS_ERROR_UNEXPECTED;
   }
-
-  JSObject *global = win->GetGlobalJSObject();
-
-  if (global) {
-    *parentObj = global;
-  }
-
-  return NS_OK;
+  return SetParentToWindow(win, parentObj);
 }
 
 // DOM Node helper
 
 template<nsresult (*func)(JSContext *cx, JSObject *obj, jsval *vp)>
 static JSBool
 GetterShim(JSContext *cx, JSObject *obj, jsid /* unused */, jsval *vp)
 {
@@ -7848,17 +7855,17 @@ nsEventTargetSH::PreCreate(nsISupports *
   nsDOMEventTargetHelper *target =
     nsDOMEventTargetHelper::FromSupports(nativeObj);
 
   nsCOMPtr<nsIScriptGlobalObject> native_parent;
   target->GetParentObject(getter_AddRefs(native_parent));
 
   *parentObj = native_parent ? native_parent->GetGlobalJSObject() : globalObj;
 
-  return NS_OK;
+  return *parentObj ? NS_OK : NS_ERROR_FAILURE;
 }
 
 NS_IMETHODIMP
 nsEventTargetSH::AddProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                              JSObject *obj, jsid id, jsval *vp, bool *_retval)
 {
   nsEventTargetSH::PreserveWrapper(GetNative(wrapper, obj));
 
@@ -10000,19 +10007,18 @@ nsHistorySH::PreCreate(nsISupports *nati
 {
   nsHistory *history = (nsHistory *)((nsIDOMHistory*)nativeObj);
   nsCOMPtr<nsPIDOMWindow> innerWindow;
   history->GetWindow(getter_AddRefs(innerWindow));
   if (!innerWindow) {
     NS_WARNING("refusing to create history object in the wrong scope");
     return NS_ERROR_FAILURE;
   }
-
-  *parentObj = static_cast<nsGlobalWindow *>(innerWindow.get())->FastGetGlobalJSObject();
-  return NS_OK;
+  return SetParentToWindow(static_cast<nsGlobalWindow *>(innerWindow.get()),
+                           parentObj);
 }
 
 NS_IMETHODIMP
 nsHistorySH::GetProperty(nsIXPConnectWrappedNative *wrapper, JSContext *cx,
                          JSObject *obj, jsid id, jsval *vp, bool *_retval)
 {
   bool is_number = false;
   GetArrayIndexFromId(cx, id, &is_number);