Bug 673331 - Add identifying information to system compartments. r=mrbkap.
authorSander van Veen <sandervv@gmail.com>
Sun, 21 Aug 2011 16:02:24 -0700
changeset 75633 09420e7880130fea54f60a9a7d4e9f038a16c9bd
parent 75632 30e7c0dfeb3a9b8aedd44f2606429edeb3ee01c7
child 75634 163bc0f5774788209945ab00cfd74faacf2291a3
push id3
push userfelipc@gmail.com
push dateFri, 30 Sep 2011 20:09:13 +0000
reviewersmrbkap
bugs673331
milestone9.0a1
Bug 673331 - Add identifying information to system compartments. r=mrbkap.
browser/components/feeds/src/FeedWriter.js
browser/components/sessionstore/content/aboutSessionRestore.js
browser/components/sessionstore/src/nsSessionStartup.js
browser/devtools/scratchpad/scratchpad.js
js/src/xpconnect/src/nsXPConnect.cpp
js/src/xpconnect/src/xpccomponents.cpp
js/src/xpconnect/src/xpcjsruntime.cpp
js/src/xpconnect/src/xpcprivate.h
netwerk/base/src/nsProxyAutoConfig.js
toolkit/mozapps/extensions/XPIProvider.jsm
--- a/browser/components/feeds/src/FeedWriter.js
+++ b/browser/components/feeds/src/FeedWriter.js
@@ -251,17 +251,18 @@ FeedWriter.prototype = {
 
   /**
    * Use this sandbox to run any dom manipulation code on nodes which
    * are already inserted into the content document.
    */
   __contentSandbox: null,
   get _contentSandbox() {
     if (!this.__contentSandbox)
-      this.__contentSandbox = new Cu.Sandbox(this._window);
+      this.__contentSandbox = new Cu.Sandbox(this._window, 
+                                             {sandboxName: 'FeedWriter'});
 
     return this.__contentSandbox;
   },
 
   /**
    * Calls doCommand for a given XUL element within the context of the
    * content document.
    *
--- a/browser/components/sessionstore/content/aboutSessionRestore.js
+++ b/browser/components/sessionstore/content/aboutSessionRestore.js
@@ -54,17 +54,17 @@ window.onload = function() {
 
   // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
   if (sessionData.value.charAt(0) == '(')
     sessionData.value = sessionData.value.slice(1, -1);
   try {
     gStateObject = JSON.parse(sessionData.value);
   }
   catch (exJSON) {
-    var s = new Cu.Sandbox("about:blank");
+    var s = new Cu.Sandbox("about:blank", {sandboxName: 'aboutSessionRestore'});
     gStateObject = Cu.evalInSandbox("(" + sessionData.value + ")", s);
     // If we couldn't parse the string with JSON.parse originally, make sure
     // that the value in the textbox will be parsable.
     sessionData.value = JSON.stringify(gStateObject);
   }
 
   // make sure the data is tracked to be restored in case of a subsequent crash
   var event = document.createEvent("UIEvents");
--- a/browser/components/sessionstore/src/nsSessionStartup.js
+++ b/browser/components/sessionstore/src/nsSessionStartup.js
@@ -130,17 +130,17 @@ SessionStartup.prototype = {
     try {
       // remove unneeded braces (added for compatibility with Firefox 2.0 and 3.0)
       if (iniString.charAt(0) == '(')
         iniString = iniString.slice(1, -1);
       try {
         this._initialState = JSON.parse(iniString);
       }
       catch (exJSON) {
-        var s = new Cu.Sandbox("about:blank");
+        var s = new Cu.Sandbox("about:blank", {sandboxName: 'nsSessionStartup'});
         this._initialState = Cu.evalInSandbox("(" + iniString + ")", s);
       }
 
       // If this is a normal restore then throw away any previous session
       if (!doResumeSessionOnce)
         delete this._initialState.lastSessionState;
     }
     catch (ex) { debug("The session file is invalid: " + ex); }
--- a/browser/devtools/scratchpad/scratchpad.js
+++ b/browser/devtools/scratchpad/scratchpad.js
@@ -173,17 +173,18 @@ var Scratchpad = {
     }
 
     if (!this._contentSandbox ||
         this.browserWindow != this._previousBrowserWindow ||
         this._previousBrowser != this.gBrowser.selectedBrowser ||
         this._previousLocation != this.gBrowser.contentWindow.location.href) {
       let contentWindow = this.gBrowser.selectedBrowser.contentWindow;
       this._contentSandbox = new Cu.Sandbox(contentWindow,
-        { sandboxPrototype: contentWindow, wantXrays: false });
+        { sandboxPrototype: contentWindow, wantXrays: false, 
+          sandboxName: 'scratchpad-content'});
 
       this._previousBrowserWindow = this.browserWindow;
       this._previousBrowser = this.gBrowser.selectedBrowser;
       this._previousLocation = contentWindow.location.href;
     }
 
     return this._contentSandbox;
   },
@@ -206,17 +207,18 @@ var Scratchpad = {
       Cu.reportError(this.strings.
                      GetStringFromName("browserWindow.unavailable"));
       return;
     }
 
     if (!this._chromeSandbox ||
         this.browserWindow != this._previousBrowserWindow) {
       this._chromeSandbox = new Cu.Sandbox(this.browserWindow,
-        { sandboxPrototype: this.browserWindow, wantXrays: false });
+        { sandboxPrototype: this.browserWindow, wantXrays: false, 
+          sandboxName: 'scratchpad-chrome'});
 
       this._previousBrowserWindow = this.browserWindow;
     }
 
     return this._chromeSandbox;
   },
 
   /**
--- a/js/src/xpconnect/src/nsXPConnect.cpp
+++ b/js/src/xpconnect/src/nsXPConnect.cpp
@@ -2068,17 +2068,18 @@ nsXPConnect::CreateSandbox(JSContext *cx
     if(!ccx.IsValid())
         return UnexpectedFailure(NS_ERROR_FAILURE);
 
     *_retval = nsnull;
 
     jsval rval = JSVAL_VOID;
     AUTO_MARK_JSVAL(ccx, &rval);
 
-    nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false);
+    nsresult rv = xpc_CreateSandboxObject(cx, &rval, principal, NULL, false, 
+                                          EmptyCString());
     NS_ASSERTION(NS_FAILED(rv) || !JSVAL_IS_PRIMITIVE(rval),
                  "Bad return value from xpc_CreateSandboxObject()!");
 
     if (NS_SUCCEEDED(rv) && !JSVAL_IS_PRIMITIVE(rval)) {
         *_retval = XPCJSObjectHolder::newHolder(ccx, JSVAL_TO_OBJECT(rval));
         NS_ENSURE_TRUE(*_retval, NS_ERROR_OUT_OF_MEMORY);
 
         NS_ADDREF(*_retval);
--- a/js/src/xpconnect/src/xpccomponents.cpp
+++ b/js/src/xpconnect/src/xpccomponents.cpp
@@ -3148,17 +3148,17 @@ class Identity : public nsISupports
 {
     NS_DECL_ISUPPORTS
 };
 
 NS_IMPL_ISUPPORTS0(Identity)
 
 nsresult
 xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop, JSObject *proto,
-                        bool wantXrays)
+                        bool wantXrays, const nsACString &sandboxName)
 {
     // Create the sandbox global object
     nsresult rv;
     nsCOMPtr<nsIXPConnect> xpc(do_GetService(nsIXPConnect::GetCID(), &rv));
     if(NS_FAILED(rv))
         return NS_ERROR_XPC_UNEXPECTED;
 
     nsCOMPtr<nsIScriptObjectPrincipal> sop(do_QueryInterface(prinOrSop));
@@ -3235,16 +3235,20 @@ xpc_CreateSandboxObject(JSContext * cx, 
 
     if (vp) {
         *vp = OBJECT_TO_JSVAL(sandbox);
         if (!WrapForSandbox(cx, wantXrays, vp)) {
             return NS_ERROR_UNEXPECTED;
         }
     }
 
+    xpc::CompartmentPrivate *compartmentPrivate =
+        static_cast<xpc::CompartmentPrivate*>(JS_GetCompartmentPrivate(cx, compartment));
+    compartmentPrivate->location = sandboxName;
+
     return NS_OK;
 }
 
 /* PRBool call(in nsIXPConnectWrappedNative wrapper,
                in JSContextPtr cx,
                in JSObjectPtr obj,
                in PRUint32 argc,
                in JSValPtr argv,
@@ -3346,16 +3350,18 @@ nsXPCComponents_utils_Sandbox::CallOrCon
         }
 
         if (!prinOrSop)
             return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
     }
 
     JSObject *proto = nsnull;
     bool wantXrays = true;
+    nsCString sandboxName;
+
     if (argc > 1) {
         if (!JSVAL_IS_OBJECT(argv[1]))
             return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
 
         JSObject *optionsObject = JSVAL_TO_OBJECT(argv[1]);
         jsval option;
 
         JSBool found;
@@ -3377,19 +3383,36 @@ nsXPCComponents_utils_Sandbox::CallOrCon
         if (found) {
             if (!JS_GetProperty(cx, optionsObject, "wantXrays", &option) ||
                 !JSVAL_IS_BOOLEAN(option)) {
                 return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
             }
 
             wantXrays = JSVAL_TO_BOOLEAN(option);
         }
+
+        if (!JS_HasProperty(cx, optionsObject, "sandboxName", &found))
+            return NS_ERROR_INVALID_ARG;
+
+        if (found) {
+            if (!JS_GetProperty(cx, optionsObject, "sandboxName", &option) ||
+                !JSVAL_IS_STRING(option)) {
+                return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
+            }
+
+            char *tmp = JS_EncodeString(cx, JSVAL_TO_STRING(option));
+            if (!tmp) {
+                return ThrowAndFail(NS_ERROR_INVALID_ARG, cx, _retval);
+            }
+
+            sandboxName.Adopt(tmp, strlen(tmp));
+        }
     }
 
-    rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays);
+    rv = xpc_CreateSandboxObject(cx, vp, prinOrSop, proto, wantXrays, sandboxName);
 
     if (NS_FAILED(rv)) {
         return ThrowAndFail(rv, cx, _retval);
     }
 
     *_retval = PR_TRUE;
 
     return rv;
--- a/js/src/xpconnect/src/xpcjsruntime.cpp
+++ b/js/src/xpconnect/src/xpcjsruntime.cpp
@@ -1573,32 +1573,40 @@ CompartmentStats::CompartmentStats(JSCon
     if(c == cx->runtime->atomsCompartment)
     {
         name.AssignLiteral("atoms");
     }
     else if(c->principals)
     {
         if(c->principals->codebase)
         {
-            // A hack: replace forward slashes with '\\' so they aren't
-            // treated as path separators.  Users of the reporters
-            // (such as about:memory) have to undo this change.
             name.Assign(c->principals->codebase);
-            name.ReplaceChar('/', '\\');
 
             // If it's the system compartment, append the address.
             // This means that multiple system compartments (and there
             // can be many) can be distinguished.
             if(c->isSystemCompartment)
             {
+                if (c->data && 
+                    !((xpc::CompartmentPrivate*)c->data)->location.IsEmpty())
+                {
+                    name.AppendLiteral(", ");
+                    name.Append(((xpc::CompartmentPrivate*)c->data)->location);
+                }
+
                 // ample; 64-bit address max is 18 chars
                 static const int maxLength = 31;
                 nsPrintfCString address(maxLength, ", 0x%llx", PRUint64(c));
                 name.Append(address);
             }
+
+            // A hack: replace forward slashes with '\\' so they aren't
+            // treated as path separators.  Users of the reporters
+            // (such as about:memory) have to undo this change.
+            name.ReplaceChar('/', '\\');
         }
         else
         {
             name.AssignLiteral("null-codebase");
         }
     }
     else
     {
--- a/js/src/xpconnect/src/xpcprivate.h
+++ b/js/src/xpconnect/src/xpcprivate.h
@@ -4310,17 +4310,17 @@ xpc_GetJSPrivate(JSObject *obj)
 // do setup etc on, puts the sandbox object in *vp (which must be
 // rooted by the caller), and uses the principal that's either
 // directly passed in prinOrSop or indirectly as an
 // nsIScriptObjectPrincipal holding the principal. If no principal is
 // reachable through prinOrSop, a new null principal will be created
 // and used.
 nsresult
 xpc_CreateSandboxObject(JSContext * cx, jsval * vp, nsISupports *prinOrSop,
-                        JSObject *proto, bool preferXray);
+                        JSObject *proto, bool preferXray, const nsACString &sandboxName);
 
 // Helper for evaluating scripts in a sandbox object created with
 // xpc_CreateSandboxObject(). The caller is responsible of ensuring
 // that *rval doesn't get collected during the call or usage after the
 // call. This helper will use filename and lineNo for error reporting,
 // and if no filename is provided it will use the codebase from the
 // principal and line number 1 as a fallback. if returnStringOnly is
 // true, then the result in *rval, or the exception in cx->exception
@@ -4389,16 +4389,17 @@ struct CompartmentPrivate
     // NB: key and ptr are mutually exclusive.
     nsAutoPtr<PtrAndPrincipalHashKey> key;
     nsCOMPtr<nsISupports> ptr;
     bool wantXrays;
     bool cycleCollectionEnabled;
     JSObject2JSObjectMap *waiverWrapperMap;
     // NB: we don't want this map to hold a strong reference to the wrapper.
     nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *> *expandoMap;
+    nsCString location;
 
     bool RegisterExpandoObject(XPCWrappedNative *wn, JSObject *expando) {
         if (!expandoMap) {
             expandoMap = new nsDataHashtable<nsPtrHashKey<XPCWrappedNative>, JSObject *>();
             if (!expandoMap->Init(8))
                 return false;
         }
         return expandoMap->Put(wn, expando);
--- a/netwerk/base/src/nsProxyAutoConfig.js
+++ b/netwerk/base/src/nsProxyAutoConfig.js
@@ -70,17 +70,18 @@ nsProxyAutoConfig.prototype = {
     init: function(pacURI, pacText) {
         // remove PAC configuration if requested
         if (pacURI == "" || pacText == "") {
             this._sandBox = null;
             return;
         }
 
         // allocate a fresh Sandbox to clear global scope for new PAC script
-        this._sandBox = new Components.utils.Sandbox(pacURI);
+        this._sandBox = new Components.utils.Sandbox(pacURI, 
+                                                     {sandboxName: 'nsProxyAutoConfig'});
         Components.utils.evalInSandbox(pacUtils, this._sandBox);
 
         // add predefined functions to pac
         this._sandBox.importFunction(myIpAddress);
         this._sandBox.importFunction(dnsResolve);
         this._sandBox.importFunction(proxyAlert, "alert");
 
         // evaluate loaded js file
--- a/toolkit/mozapps/extensions/XPIProvider.jsm
+++ b/toolkit/mozapps/extensions/XPIProvider.jsm
@@ -3456,32 +3456,36 @@ var XPIProvider = {
     this.bootstrappedAddons[aId] = {
       version: aVersion,
       descriptor: aFile.persistentDescriptor
     };
     this.addAddonsToCrashReporter();
 
     let principal = Cc["@mozilla.org/systemprincipal;1"].
                     createInstance(Ci.nsIPrincipal);
-    this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal);
 
     if (!aFile.exists()) {
+      this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
+                                                               {sandboxName: aFile.path});
       ERROR("Attempted to load bootstrap scope from missing directory " + bootstrap.path);
       return;
     }
 
+    let uri = getURIForResourceInFile(aFile, "bootstrap.js").spec;
+    this.bootstrapScopes[aId] = new Components.utils.Sandbox(principal,
+                                                             {sandboxName: uri});
+
     let loader = Cc["@mozilla.org/moz/jssubscript-loader;1"].
                  createInstance(Ci.mozIJSSubScriptLoader);
 
     try {
       // As we don't want our caller to control the JS version used for the
       // bootstrap file, we run loadSubScript within the context of the
       // sandbox with the latest JS version set explicitly.
-      this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ =
-          getURIForResourceInFile(aFile, "bootstrap.js").spec;
+      this.bootstrapScopes[aId].__SCRIPT_URI_SPEC__ = uri;
       Components.utils.evalInSandbox(
         "Components.classes['@mozilla.org/moz/jssubscript-loader;1'] \
                    .createInstance(Components.interfaces.mozIJSSubScriptLoader) \
                    .loadSubScript(__SCRIPT_URI_SPEC__);", this.bootstrapScopes[aId], "ECMAv5");
     }
     catch (e) {
       WARN("Error loading bootstrap.js for " + aId, e);
     }