bug 580128 - Avoid using the parent chain of proxies for anything because it's often wrong. r=jst
authorBlake Kaplan <mrbkap@gmail.com>
Fri, 24 Sep 2010 18:00:58 -0700
changeset 55604 c42a624a877c66721a8a4b827bae87be66740b0d
parent 55603 b886c3138d751b8e3cd6833def03c801c3475446
child 55605 e167ad4febd670ad1534bcd264e94cfc96bdb667
push idunknown
push userunknown
push dateunknown
reviewersjst
bugs580128
milestone2.0b8pre
bug 580128 - Avoid using the parent chain of proxies for anything because it's often wrong. r=jst
caps/src/nsSecurityManagerFactory.cpp
dom/base/nsDOMClassInfo.cpp
dom/base/nsGlobalWindow.cpp
dom/base/nsJSEnvironment.cpp
js/src/xpconnect/src/xpcwrappedjsclass.cpp
js/src/xpconnect/src/xpcwrappednative.cpp
js/src/xpconnect/wrappers/AccessCheck.cpp
js/src/xpconnect/wrappers/AccessCheck.h
js/src/xpconnect/wrappers/WrapperFactory.cpp
--- a/caps/src/nsSecurityManagerFactory.cpp
+++ b/caps/src/nsSecurityManagerFactory.cpp
@@ -47,16 +47,17 @@
 #include "nsIScriptContext.h"
 #include "nsICategoryManager.h"
 #include "nsXPIDLString.h"
 #include "nsCOMPtr.h"
 #include "nsIServiceManager.h"
 #include "nsString.h"
 #include "nsNetCID.h"
 #include "nsIClassInfoImpl.h"
+#include "jsobj.h"
 
 ///////////////////////
 // nsSecurityNameSet //
 ///////////////////////
 
 nsSecurityNameSet::nsSecurityNameSet()
 {
 }
@@ -289,16 +290,17 @@ static JSFunctionSpec PrivilegeManager_s
  * "Steal" calls to netscape.security.PrivilegeManager.enablePrivilege,
  * et. al. so that code that worked with 4.0 can still work.
  */
 NS_IMETHODIMP 
 nsSecurityNameSet::InitializeNameSet(nsIScriptContext* aScriptContext)
 {
     JSContext *cx = (JSContext *) aScriptContext->GetNativeContext();
     JSObject *global = JS_GetGlobalObject(cx);
+    OBJ_TO_INNER_OBJECT(cx, global);
 
     /*
      * Find Object.prototype's class by walking up the global object's
      * prototype chain.
      */
     JSObject *obj = global;
     JSObject *proto;
     JSAutoRequest ar(cx);
--- a/dom/base/nsDOMClassInfo.cpp
+++ b/dom/base/nsDOMClassInfo.cpp
@@ -5248,19 +5248,27 @@ nsWindowSH::GetProperty(nsIXPConnectWrap
       // check and return.
 
       nsGlobalWindow *frameWin = (nsGlobalWindow *)frame.get();
       NS_ASSERTION(frameWin->IsOuterWindow(), "GetChildFrame gave us an inner?");
 
       frameWin->EnsureInnerWindow();
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
+      jsval v;
       rv = WrapNative(cx, frameWin->GetGlobalJSObject(), frame,
-                      &NS_GET_IID(nsIDOMWindow), PR_TRUE, vp,
+                      &NS_GET_IID(nsIDOMWindow), PR_TRUE, &v,
                       getter_AddRefs(holder));
+      NS_ENSURE_SUCCESS(rv, rv);
+
+      if (!JS_WrapValue(cx, &v)) {
+        return NS_ERROR_FAILURE;
+      }
+
+      *vp = v;
     }
 
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }
 
   if (JSID_IS_STRING(id) && !JSVAL_IS_PRIMITIVE(*vp) &&
       ::JS_TypeOfValue(cx, *vp) != JSTYPE_FUNCTION) {
     // A named property accessed which could have been resolved to a
@@ -6795,18 +6803,19 @@ nsWindowSH::NewResolve(nsIXPConnectWrapp
       nsCOMPtr<nsIDOMDocument> document;
       rv = win->GetDocument(getter_AddRefs(document));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // FIXME Ideally we'd have an nsIDocument here and get nsWrapperCache
       //       from it.
       jsval v;
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-      rv = WrapNative(cx, obj, document, &NS_GET_IID(nsIDOMDocument), PR_FALSE,
-                      &v, getter_AddRefs(holder));
+      rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), document,
+                      &NS_GET_IID(nsIDOMDocument), PR_FALSE, &v,
+                      getter_AddRefs(holder));
       NS_ENSURE_SUCCESS(rv, rv);
 
       // The PostCreate hook for the document will handle defining the
       // property
       *objp = obj;
 
       if (ObjectIsNativeWrapper(cx, obj)) {
         // Unless our object is a native wrapper, in which case we have to
@@ -7313,29 +7322,30 @@ nsNodeSH::GetProperty(nsIXPConnectWrappe
       nsCOMPtr<nsIDocument> doc = do_QueryWrappedNative(wrapper, obj);
       NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
 
       uri = doc->GetBaseURI();
       NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
     }
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsresult rv = WrapNative(cx, obj, uri, &NS_GET_IID(nsIURI), PR_TRUE, vp,
+    nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri,
+                             &NS_GET_IID(nsIURI), PR_TRUE, vp,
                              getter_AddRefs(holder));
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }
 
   if (id == sNodePrincipal_id && IsPrivilegedScript()) {
     nsCOMPtr<nsINode> node = do_QueryWrappedNative(wrapper, obj);
     NS_ENSURE_TRUE(node, NS_ERROR_UNEXPECTED);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsresult rv = WrapNative(cx, obj, node->NodePrincipal(),
-                             &NS_GET_IID(nsIPrincipal), PR_TRUE, vp,
-                             getter_AddRefs(holder));
+    nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx),
+                             node->NodePrincipal(), &NS_GET_IID(nsIPrincipal),
+                             PR_TRUE, vp, getter_AddRefs(holder));
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }    
 
   // Note: none of our ancestors want GetProperty
   return NS_OK;
 }
 
 NS_IMETHODIMP
@@ -7943,17 +7953,18 @@ nsArraySH::GetProperty(nsIXPConnectWrapp
     // don't have to set rv.
     rv = NS_OK;
     nsWrapperCache *cache = nsnull;
     nsISupports* array_item =
       GetItemAt(GetNative(wrapper, obj), n, &cache, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (array_item) {
-      rv = WrapNative(cx, obj, array_item, cache, PR_TRUE, vp);
+      rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), array_item, cache,
+                      PR_TRUE, vp);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = NS_SUCCESS_I_DID_SOMETHING;
     }
   }
 
   return rv;
 }
@@ -8063,17 +8074,18 @@ nsNamedArraySH::GetProperty(nsIXPConnect
   if (JSID_IS_STRING(id) && !ObjectIsNativeWrapper(cx, obj)) {
     nsresult rv = NS_OK;
     nsWrapperCache *cache = nsnull;
     nsISupports* item = GetNamedItem(GetNative(wrapper, obj),
                                      nsDependentJSString(id), &cache, &rv);
     NS_ENSURE_SUCCESS(rv, rv);
 
     if (item) {
-      rv = WrapNative(cx, obj, item, cache, PR_TRUE, vp);
+      rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), item, cache,
+                      PR_TRUE, vp);
       NS_ENSURE_SUCCESS(rv, rv);
 
       rv = NS_SUCCESS_I_DID_SOMETHING;
     }
 
     // Don't fall through to nsArraySH::GetProperty() here
     return rv;
   }
@@ -8238,18 +8250,19 @@ nsDocumentSH::NewResolve(nsIXPConnectWra
 
     nsCOMPtr<nsIDOMLocation> location;
     rv = doc->GetLocation(getter_AddRefs(location));
     NS_ENSURE_SUCCESS(rv, rv);
 
     jsval v;
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
-                    &v, getter_AddRefs(holder));
+    rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
+                    &NS_GET_IID(nsIDOMLocation), PR_TRUE, &v,
+                    getter_AddRefs(holder));
     NS_ENSURE_SUCCESS(rv, rv);
 
     JSAutoRequest ar(cx);
 
     JSBool ok = ::JS_DefinePropertyById(cx, obj, id, v, nsnull, nsnull,
                                         JSPROP_PERMANENT | JSPROP_ENUMERATE);
 
     if (!ok) {
@@ -8275,17 +8288,18 @@ nsDocumentSH::GetProperty(nsIXPConnectWr
   if (id == sDocumentURIObject_id && IsPrivilegedScript()) {
     nsCOMPtr<nsIDocument> doc = do_QueryWrappedNative(wrapper);
     NS_ENSURE_TRUE(doc, NS_ERROR_UNEXPECTED);
 
     nsIURI* uri = doc->GetDocumentURI();
     NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    nsresult rv = WrapNative(cx, obj, uri, &NS_GET_IID(nsIURI), PR_TRUE, vp,
+    nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), uri,
+                             &NS_GET_IID(nsIURI), PR_TRUE, vp,
                              getter_AddRefs(holder));
 
     return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
   }
 
   return nsNodeSH::GetProperty(wrapper, cx, obj, id, vp, _retval);
 }
 
@@ -8307,18 +8321,19 @@ nsDocumentSH::SetProperty(nsIXPConnectWr
 
       JSString *val = ::JS_ValueToString(cx, *vp);
       NS_ENSURE_TRUE(val, NS_ERROR_UNEXPECTED);
 
       rv = location->SetHref(nsDependentJSString(val));
       NS_ENSURE_SUCCESS(rv, rv);
 
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-      rv = WrapNative(cx, obj, location, &NS_GET_IID(nsIDOMLocation), PR_TRUE,
-                      vp, getter_AddRefs(holder));
+      rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), location,
+                      &NS_GET_IID(nsIDOMLocation), PR_TRUE, vp,
+                      getter_AddRefs(holder));
       return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
     }
   }
 
   if (id == sDocumentURIObject_id && IsPrivilegedScript()) {
     // We don't want privileged script that can read this property to set it,
     // but _do_ want to allow everyone else to set a value they can then read.
     //
@@ -8461,21 +8476,17 @@ nsHTMLDocumentSH::DocumentOpen(JSContext
   nsCOMPtr<nsIDOMDocument> retval;
   nsresult rv = doc->Open(contentType, replace, getter_AddRefs(retval));
   if (NS_FAILED(rv)) {
     nsDOMClassInfo::ThrowJSException(cx, rv);
 
     return JS_FALSE;
   }
 
-  nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-  rv = WrapNative(cx, obj, retval, PR_FALSE, vp,
-                  getter_AddRefs(holder));
-  NS_ASSERTION(NS_SUCCEEDED(rv), "Failed to wrap native!");
-
+  *vp = OBJECT_TO_JSVAL(obj);
   return NS_SUCCEEDED(rv);
 }
 
 
 static JSClass sHTMLDocumentAllClass = {
   "HTML document.all class",
   JSCLASS_HAS_PRIVATE | JSCLASS_PRIVATE_IS_NSISUPPORTS | JSCLASS_NEW_RESOLVE |
   JSCLASS_HAS_RESERVED_SLOTS(1),
@@ -8541,30 +8552,31 @@ nsHTMLDocumentSH::GetDocumentAllNodeList
 
     nsRefPtr<nsContentList> list =
       domdoc->GetElementsByTagName(NS_LITERAL_STRING("*"));
     if (!list) {
       rv |= NS_ERROR_OUT_OF_MEMORY;
     }
 
     nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-    rv |= nsDOMClassInfo::WrapNative(cx, obj, static_cast<nsINodeList*>(list),
+    rv |= nsDOMClassInfo::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
+                                     static_cast<nsINodeList*>(list),
                                      list, PR_FALSE, &collection,
                                      getter_AddRefs(holder));
 
     list.forget(nodeList);
 
     // ... and store it in our reserved slot.
     if (!JS_SetReservedSlot(cx, obj, 0, collection)) {
       return JS_FALSE;
     }
   }
 
   if (NS_FAILED(rv)) {
-    nsDOMClassInfo::ThrowJSException(cx, rv);
+    nsDOMClassInfo::ThrowJSException(cx, NS_ERROR_FAILURE);
 
     return JS_FALSE;
   }
 
   return *nodeList != nsnull;
 }
 
 JSBool
@@ -8644,17 +8656,17 @@ nsHTMLDocumentSH::DocumentAllGetProperty
 
     nsIContent *node = nodeList->GetNodeAt(JSID_TO_INT(id));
 
     result = node;
     cache = node;
   }
 
   if (result) {
-    rv = WrapNative(cx, obj, result, cache, PR_TRUE, vp);
+    rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), result, cache, PR_TRUE, vp);
     if (NS_FAILED(rv)) {
       nsDOMClassInfo::ThrowJSException(cx, rv);
 
       return JS_FALSE;
     }
   } else {
     *vp = JSVAL_VOID;
   }
@@ -8917,17 +8929,17 @@ nsHTMLDocumentSH::DocumentAllTagsNewReso
     }
 
     nsRefPtr<nsContentList> tags =
       doc->GetElementsByTagName(nsDependentJSString(str));
 
     if (tags) {
       jsval v;
       nsCOMPtr<nsIXPConnectJSObjectHolder> holder;
-      nsresult rv = nsDOMClassInfo::WrapNative(cx, obj,
+      nsresult rv = nsDOMClassInfo::WrapNative(cx, JS_GetGlobalForScopeChain(cx),
                                                static_cast<nsINodeList*>(tags),
                                                tags, PR_TRUE, &v,
                                                getter_AddRefs(holder));
       if (NS_FAILED(rv)) {
         nsDOMClassInfo::ThrowJSException(cx, rv);
 
         return JS_FALSE;
       }
@@ -9175,17 +9187,18 @@ nsHTMLFormElementSH::GetProperty(nsIXPCo
     PRInt32 n = GetArrayIndexFromId(cx, id);
 
     if (n >= 0) {
       nsIFormControl* control = form->GetElementAt(n);
 
       if (control) {
         Element *element =
           static_cast<nsGenericHTMLFormElement*>(form->GetElementAt(n));
-        nsresult rv = WrapNative(cx, obj, element, element, PR_TRUE, vp);
+        nsresult rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), element,
+                                 element, PR_TRUE, vp);
         return NS_FAILED(rv) ? rv : NS_SUCCESS_I_DID_SOMETHING;
       }
     }
   }
 
   return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);;
 }
 
@@ -9280,17 +9293,18 @@ nsHTMLSelectElementSH::GetProperty(nsIXP
     nsHTMLSelectElement *s =
       nsHTMLSelectElement::FromSupports(GetNative(wrapper, obj));
 
     nsHTMLOptionCollection *options = s->GetOptions();
 
     if (options) {
       nsISupports *node = options->GetNodeAt(n, &rv);
 
-      rv = WrapNative(cx, obj, node, &NS_GET_IID(nsIDOMNode), PR_TRUE, vp);
+      rv = WrapNative(cx, JS_GetGlobalForScopeChain(cx), node,
+                      &NS_GET_IID(nsIDOMNode), PR_TRUE, vp);
       if (NS_SUCCEEDED(rv)) {
         rv = NS_SUCCESS_I_DID_SOMETHING;
       }
       return rv;
     }
   }
 
   return nsElementSH::GetProperty(wrapper, cx, obj, id, vp, _retval);;
--- a/dom/base/nsGlobalWindow.cpp
+++ b/dom/base/nsGlobalWindow.cpp
@@ -1938,19 +1938,35 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       if (!outerObject) {
         NS_ERROR("unable to transplant wrappers, probably OOM");
         return NS_ERROR_FAILURE;
       }
 
       mJSObject = outerObject;
       SetWrapper(mJSObject);
 
+      {
+        JSAutoEnterCompartment ac;
+        if (!ac.enter(cx, mJSObject)) {
+          NS_ERROR("unable to enter a compartment");
+          return NS_ERROR_FAILURE;
+        }
+
+        JS_SetParent(cx, mJSObject, newInnerWindow->mJSObject);
+      }
+
       mContext->SetOuterObject(mJSObject);
     }
 
+    JSAutoEnterCompartment ac;
+    if (!ac.enter(cx, mJSObject)) {
+      NS_ERROR("unable to enter a compartment");
+      return NS_ERROR_FAILURE;
+    }
+
     // XXX Not sure if this is needed.
     if (aState) {
       JSObject *proto;
       if (nsIXPConnectJSObjectHolder *holder = wsh->GetOuterRealProto()) {
         holder->GetJSObject(&proto);
       } else {
         proto = nsnull;
       }
@@ -1969,26 +1985,16 @@ nsGlobalWindow::SetNewDocument(nsIDocume
       }
     }
   }
 
   if (!aState && !reUseInnerWindow) {
     // Loading a new page and creating a new inner window, *not*
     // restoring from session history.
 
-    // InitClassesWithNewWrappedGlobal() (via CreateNativeGlobalForInner)
-    // for the new inner window
-    // sets the global object in cx to be the new wrapped global. We
-    // don't want that, but re-initializing the outer window will
-    // fix that for us. And perhaps more importantly, this will
-    // ensure that the outer window gets a new prototype so we don't
-    // leak prototype properties from the old inner window to the
-    // new one.
-    mContext->InitOuterWindow();
-
     // Now that both the the inner and outer windows are initialized
     // let the script context do its magic to hook them together.
     mContext->ConnectToInner(newInnerWindow, mJSObject);
 
     nsCOMPtr<nsIContent> frame = do_QueryInterface(GetFrameElementInternal());
     if (frame && frame->GetOwnerDoc()) {
       nsPIDOMWindow* parentWindow = frame->GetOwnerDoc()->GetWindow();
       if (parentWindow && parentWindow->TimeoutSuspendCount()) {
@@ -2037,17 +2043,17 @@ nsGlobalWindow::SetNewDocument(nsIDocume
         // XXXmarkh - tell other languages about this?
         ::JS_DeleteProperty(cx, currentInner->mJSObject, "document");
       }
     } else {
       rv = newInnerWindow->InnerSetNewDocument(aDocument);
       NS_ENSURE_SUCCESS(rv, rv);
 
       // Initialize DOM classes etc on the inner window.
-      rv = mContext->InitClasses(mJSObject);
+      rv = mContext->InitClasses(newInnerWindow->mJSObject);
       NS_ENSURE_SUCCESS(rv, rv);
 
       if (navigatorHolder) {
         // Restore window.navigator onto the new inner window.
 
         ::JS_DefineProperty(cx, newInnerWindow->mJSObject, "navigator",
                             nav, nsnull, nsnull,
                             JSPROP_ENUMERATE | JSPROP_PERMANENT |
--- a/dom/base/nsJSEnvironment.cpp
+++ b/dom/base/nsJSEnvironment.cpp
@@ -2520,35 +2520,36 @@ nsJSContext::ConnectToInner(nsIScriptGlo
   // "window."). XPConnect looks up the wrapper based on the
   // function object's parent, which is the object the function
   // was called on, and when calling alert() we'll be calling the
   // alert() function from the outer window's prototype off of the
   // inner window. In this case XPConnect is able to find the
   // outer (through the JSExtendedClass hook outerObject), so this
   // prototype sharing works.
 
+  // Now that we're connecting the outer global to the inner one,
+  // we must have transplanted it. The JS engine tries to maintain
+  // the global object's compartment as its default compartment,
+  // so update that now since it might have changed.
+  JS_SetGlobalObject(mContext, outerGlobal);
+
   // We do *not* want to use anything else out of the outer
   // object's prototype chain than the first prototype, which is
   // the XPConnect prototype. The rest we want from the inner
   // window's prototype, i.e. the global scope polluter and
   // Object.prototype. This way the outer also gets the benefits
   // of the global scope polluter, and the inner window's
   // Object.prototype.
   JSObject *proto = JS_GetPrototype(mContext, outerGlobal);
   JSObject *innerProto = JS_GetPrototype(mContext, newInnerJSObject);
   JSObject *innerProtoProto = JS_GetPrototype(mContext, innerProto);
 
   JS_SetPrototype(mContext, newInnerJSObject, proto);
   JS_SetPrototype(mContext, proto, innerProtoProto);
 
-  // Now that we're connecting the outer global to the inner one,
-  // we must have transplanted it. The JS engine tries to maintain
-  // the global object's compartment as its default compartment,
-  // so update that now since it might have changed.
-  JS_SetGlobalObject(mContext, outerGlobal);
   return NS_OK;
 }
 
 void *
 nsJSContext::GetNativeContext()
 {
   return mContext;
 }
@@ -2634,16 +2635,17 @@ nsJSContext::SetOuterObject(void *aOuter
   JS_SetGlobalObject(mContext, outer);
   return NS_OK;
 }
 
 nsresult
 nsJSContext::InitOuterWindow()
 {
   JSObject *global = JS_GetGlobalObject(mContext);
+  OBJ_TO_INNER_OBJECT(mContext, global);
 
   nsresult rv = InitClasses(global); // this will complete global object initialization
   NS_ENSURE_SUCCESS(rv, rv);
 
   return NS_OK;
 }
 
 nsresult
--- a/js/src/xpconnect/src/xpcwrappedjsclass.cpp
+++ b/js/src/xpconnect/src/xpcwrappedjsclass.cpp
@@ -40,16 +40,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 /* Sharable code and data for wrapper around JSObjects. */
 
 #include "xpcprivate.h"
 #include "nsArrayEnumerator.h"
 #include "nsWrapperCache.h"
 #include "XPCWrapper.h"
+#include "AccessCheck.h"
 
 NS_IMPL_THREADSAFE_ISUPPORTS1(nsXPCWrappedJSClass, nsIXPCWrappedJSClass)
 
 // the value of this variable is never used - we use its address as a sentinel
 static uint32 zero_methods_descriptor;
 
 void AutoScriptEvaluate::StartEvaluating(JSErrorReporter errorReporter)
 {
@@ -252,32 +253,19 @@ nsXPCWrappedJSClass::CallQueryInterfaceO
     if(!ac.enter(cx, jsobj))
         return nsnull;
 
     // Don't call the actual function on a content object. We'll determine
     // whether or not a content object is capable of implementing the
     // interface (i.e. whether the interface is scriptable) and most content
     // objects don't have QI implementations anyway. Also see bug 503926.
     if(XPCPerThreadData::IsMainThread(ccx) &&
-       !JS_GetGlobalForObject(ccx, jsobj)->isSystem())
+       !xpc::AccessCheck::isChrome(jsobj->getCompartment(ccx)))
     {
-        nsCOMPtr<nsIPrincipal> objprin;
-        nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
-        if(ssm)
-        {
-            nsresult rv = ssm->GetObjectPrincipal(ccx, jsobj, getter_AddRefs(objprin));
-            NS_ENSURE_SUCCESS(rv, nsnull);
-
-            PRBool isSystem;
-            rv = ssm->IsSystemPrincipal(objprin, &isSystem);
-            NS_ENSURE_SUCCESS(rv, nsnull);
-
-            if(!isSystem)
-                return nsnull;
-        }
+        return nsnull;
     }
 
     // check upfront for the existence of the function property
     funid = mRuntime->GetStringID(XPCJSRuntime::IDX_QUERY_INTERFACE);
     if(!JS_GetPropertyById(cx, jsobj, funid, &fun) || JSVAL_IS_PRIMITIVE(fun))
         return nsnull;
 
     // protect fun so that we're sure it's alive when we call it
@@ -1330,21 +1318,22 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
     scriptEval.StartEvaluating(xpcWrappedJSErrorReporter);
 
     xpcc->SetPendingResult(pending_result);
     xpcc->SetException(nsnull);
     ccx.GetThreadData()->SetException(nsnull);
 
     if(XPCPerThreadData::IsMainThread(ccx))
     {
+        // TODO Remove me in favor of security wrappers.
         nsIScriptSecurityManager *ssm = XPCWrapper::GetSecurityManager();
         if(ssm)
         {
-            nsCOMPtr<nsIPrincipal> objPrincipal;
-            ssm->GetObjectPrincipal(ccx, obj, getter_AddRefs(objPrincipal));
+            nsIPrincipal *objPrincipal =
+                xpc::AccessCheck::getPrincipal(obj->getCompartment(ccx));
             if(objPrincipal)
             {
                 JSStackFrame* fp = nsnull;
                 nsresult rv =
                     ssm->PushContextPrincipal(ccx, JS_FrameIterator(ccx, &fp),
                                               objPrincipal);
                 if(NS_FAILED(rv))
                 {
@@ -1510,16 +1499,23 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
         }
     }
     else if(JSVAL_IS_OBJECT(fval))
     {
         ccx.SetCallee(JSVAL_TO_OBJECT(fval));
     }
 
     // build the args
+    // NB: This assignment *looks* wrong because we haven't yet called our
+    // function. However, we *have* already entered the compartmen that we're
+    // about to call, and that's the global that we want here. In other words:
+    // we're trusting the JS engine to come up with a good global to use for
+    // our object (whatever it was).
+    JSObject *scopeobj;
+    scopeobj = JS_GetGlobalForScopeChain(ccx);
     for(i = 0; i < argc; i++)
     {
         const nsXPTParamInfo& param = info->params[i];
         const nsXPTType& type = param.GetType();
         nsXPTType datum_type;
         JSUint32 array_count;
         PRBool isArray = type.IsArray();
         jsval val = JSVAL_NULL;
@@ -1570,39 +1566,39 @@ nsXPCWrappedJSClass::CallMethod(nsXPCWra
             }
 
             if(isArray)
             {
                 XPCLazyCallContext lccx(ccx);
                 if(!XPCConvert::NativeArray2JS(lccx, &val,
                                                (const void**)&pv->val,
                                                datum_type, &param_iid,
-                                               array_count, obj, nsnull))
+                                               array_count, scopeobj, nsnull))
                     goto pre_call_clean_up;
             }
             else if(isSizedString)
             {
                 if(!XPCConvert::NativeStringWithSize2JS(ccx, &val,
                                                (const void*)&pv->val,
                                                datum_type,
                                                array_count, nsnull))
                     goto pre_call_clean_up;
             }
             else
             {
                 if(!XPCConvert::NativeData2JS(ccx, &val, &pv->val, type,
-                                              &param_iid, obj, nsnull))
+                                              &param_iid, scopeobj, nsnull))
                     goto pre_call_clean_up;
             }
         }
 
         if(param.IsOut() || param.IsDipper())
         {
             // create an 'out' object
-            JSObject* out_obj = NewOutObject(cx, obj);
+            JSObject* out_obj = NewOutObject(cx, scopeobj);
             if(!out_obj)
             {
                 retval = NS_ERROR_OUT_OF_MEMORY;
                 goto pre_call_clean_up;
             }
 
             if(param.IsIn())
             {
--- a/js/src/xpconnect/src/xpcwrappednative.cpp
+++ b/js/src/xpconnect/src/xpcwrappednative.cpp
@@ -46,16 +46,17 @@
 #include "XPCNativeWrapper.h"
 #include "XPCWrapper.h"
 #include "nsWrapperCache.h"
 #include "xpclog.h"
 #include "jstl.h"
 #include "nsINode.h"
 #include "xpcquickstubs.h"
 #include "jsproxy.h"
+#include "AccessCheck.h"
 
 /***************************************************************************/
 
 NS_IMPL_CYCLE_COLLECTION_CLASS(XPCWrappedNative)
 
 NS_IMETHODIMP
 NS_CYCLE_COLLECTION_CLASSNAME(XPCWrappedNative)::RootAndUnlinkJSObjects(void *p)
 {
@@ -513,19 +514,18 @@ XPCWrappedNative::GetNewOrUsed(XPCCallCo
             return NS_ERROR_FAILURE;
 
         nsISupports *Object = helper.Object();
         if(nsXPCWrappedJSClass::IsWrappedJS(Object))
         {
             nsCOMPtr<nsIXPConnectWrappedJS> wrappedjs(do_QueryInterface(Object));
             JSObject *obj;
             wrappedjs->GetJSObject(&obj);
-            if((obj->isSystem() ||
-                JS_GetGlobalForObject(ccx, obj)->isSystem()) &&
-               !Scope->GetGlobalJSObject()->isSystem())
+            if(xpc::AccessCheck::isChrome(obj->getCompartment(ccx)) &&
+               !xpc::AccessCheck::isChrome(Scope->GetGlobalJSObject()->getCompartment(ccx)))
             {
                 needsCOW = JS_TRUE;
             }
         }
     }
 
     AutoMarkingWrappedNativeProtoPtr proto(ccx);
 
--- a/js/src/xpconnect/wrappers/AccessCheck.cpp
+++ b/js/src/xpconnect/wrappers/AccessCheck.cpp
@@ -71,16 +71,22 @@ AccessCheck::isChrome(JSCompartment *com
         return false;
     }
 
     PRBool privileged;
     nsIPrincipal *principal = GetCompartmentPrincipal(compartment);
     return NS_SUCCEEDED(ssm->IsSystemPrincipal(principal, &privileged)) && privileged;
 }
 
+nsIPrincipal *
+AccessCheck::getPrincipal(JSCompartment *compartment)
+{
+    return GetCompartmentPrincipal(compartment);
+}
+
 #define NAME(ch, str, cases) case ch: if (!strcmp(name, str)) switch (prop[0]) { cases }; break;
 #define PROP(ch, actions) case ch: { actions }; break;
 #define RW(str) if (!strcmp(prop, str)) return true;
 #define R(str) if (!set && !strcmp(prop, str)) return true;
 #define W(str) if (set && !strcmp(prop, str)) return true;
 
 // Hardcoded policy for cross origin property access. This was culled from the
 // preferences file (all.js). We don't want users to overwrite highly sensitive
--- a/js/src/xpconnect/wrappers/AccessCheck.h
+++ b/js/src/xpconnect/wrappers/AccessCheck.h
@@ -35,22 +35,25 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "jsapi.h"
 #include "jswrapper.h"
 
+class nsIPrincipal;
+
 namespace xpc {
 
 class AccessCheck {
   public:
     static bool isSameOrigin(JSCompartment *a, JSCompartment *b);
     static bool isChrome(JSCompartment *compartment);
+    static nsIPrincipal *getPrincipal(JSCompartment *compartment);
     static bool isCrossOriginAccessPermitted(JSContext *cx, JSObject *obj, jsid id,
                                              JSWrapper::Action act);
     static bool isSystemOnlyAccessPermitted(JSContext *cx);
 
     static bool needsSystemOnlyWrapper(JSObject *obj);
 
     static void deny(JSContext *cx, jsid id);
 };
--- a/js/src/xpconnect/wrappers/WrapperFactory.cpp
+++ b/js/src/xpconnect/wrappers/WrapperFactory.cpp
@@ -133,17 +133,17 @@ WrapperFactory::Rewrap(JSContext *cx, JS
             wrapper = &FilteringWrapper<Xray,
                                         CrossOriginAccessiblePropertiesOnly>::singleton;
             xrayHolder = Xray::createHolder(cx, obj, parent);
             if (!xrayHolder)
                 return nsnull;
         }
     }
 
-    JSObject *wrapperObj = JSWrapper::New(cx, obj, wrappedProto, NULL, wrapper);
+    JSObject *wrapperObj = JSWrapper::New(cx, obj, wrappedProto, parent, wrapper);
     if (!wrapperObj || !xrayHolder)
         return wrapperObj;
     wrapperObj->setProxyExtra(js::ObjectValue(*xrayHolder));
     xrayHolder->setSlot(XrayUtils::JSSLOT_PROXY_OBJ, js::ObjectValue(*wrapperObj));
     return wrapperObj;
 }
 
 }