Bug 1039034 - Don't leak add-on interpositions at shutdown (r=bholley)
authorBill McCloskey <wmccloskey@mozilla.com>
Fri, 18 Jul 2014 16:50:55 -0700
changeset 217028 356c0e9159457142755ab166338f07458f6dc6b0
parent 217027 8614bc69e2903dbfd07fad671f28b0e42fa7f266
child 217029 f875dc5e0df7ff0e95a6d0a7fc5527d260315749
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley
bugs1039034
milestone33.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 1039034 - Don't leak add-on interpositions at shutdown (r=bholley)
js/xpconnect/src/XPCWrappedNativeScope.cpp
js/xpconnect/src/xpcprivate.h
--- a/js/xpconnect/src/XPCWrappedNativeScope.cpp
+++ b/js/xpconnect/src/XPCWrappedNativeScope.cpp
@@ -22,16 +22,36 @@ using namespace xpc;
 using namespace JS;
 
 /***************************************************************************/
 
 XPCWrappedNativeScope* XPCWrappedNativeScope::gScopes = nullptr;
 XPCWrappedNativeScope* XPCWrappedNativeScope::gDyingScopes = nullptr;
 XPCWrappedNativeScope::InterpositionMap* XPCWrappedNativeScope::gInterpositionMap = nullptr;
 
+NS_IMPL_ISUPPORTS(XPCWrappedNativeScope::ClearInterpositionsObserver, nsIObserver)
+
+NS_IMETHODIMP
+XPCWrappedNativeScope::ClearInterpositionsObserver::Observe(nsISupports *subject,
+                                                            const char *topic,
+                                                            const char16_t *data)
+{
+    MOZ_ASSERT(strcmp(topic, NS_XPCOM_SHUTDOWN_OBSERVER_ID) == 0);
+
+    // The interposition map holds strong references to interpositions, which
+    // may themselves be involved in cycles. We need to drop these strong
+    // references before the cycle collector shuts down. Otherwise we'll
+    // leak. This observer always runs before CC shutdown.
+    if (gInterpositionMap)
+        delete gInterpositionMap;
+
+    nsContentUtils::UnregisterShutdownObserver(this);
+    return NS_OK;
+}
+
 static bool
 RemoteXULForbidsXBLScope(nsIPrincipal *aPrincipal, HandleObject aGlobal)
 {
   MOZ_ASSERT(aPrincipal);
 
   // The SafeJSContext is lazily created, and tends to be created at really
   // weird times, at least for xpcshell (often very early in startup or late
   // in shutdown). Its scope isn't system principal, so if we proceeded we'd
@@ -666,19 +686,16 @@ XPCWrappedNativeScope::SystemIsBeingShut
         cur->mWrappedNativeProtoMap->
                 Enumerate(WrappedNativeProtoShutdownEnumerator,  &data);
         cur->mWrappedNativeMap->
                 Enumerate(WrappedNativeShutdownEnumerator,  &data);
     }
 
     // Now it is safe to kill all the scopes.
     KillDyingScopes();
-
-    if (gInterpositionMap)
-        delete gInterpositionMap;
 }
 
 
 /***************************************************************************/
 
 JSObject *
 XPCWrappedNativeScope::GetExpandoChain(HandleObject target)
 {
@@ -702,16 +719,19 @@ XPCWrappedNativeScope::SetExpandoChain(J
 
 /* static */ bool
 XPCWrappedNativeScope::SetAddonInterposition(JSAddonId *addonId,
                                              nsIAddonInterposition *interp)
 {
     if (!gInterpositionMap) {
         gInterpositionMap = new InterpositionMap();
         gInterpositionMap->init();
+
+        // Make sure to clear the map at shutdown.
+        nsContentUtils::RegisterShutdownObserver(new ClearInterpositionsObserver());
     }
     if (interp) {
         return gInterpositionMap->put(addonId, interp);
     } else {
         gInterpositionMap->remove(addonId);
         return true;
     }
 }
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -105,16 +105,17 @@
 #include "nsIComponentManager.h"
 #include "nsIComponentRegistrar.h"
 #include "nsISupportsPrimitives.h"
 #include "nsMemory.h"
 #include "nsIXPConnect.h"
 #include "nsIInterfaceInfo.h"
 #include "nsIXPCScriptable.h"
 #include "nsIJSRuntimeService.h"
+#include "nsIObserver.h"
 #include "nsWeakReference.h"
 #include "nsCOMPtr.h"
 #include "nsXPTCUtils.h"
 #include "xptinfo.h"
 #include "XPCForwards.h"
 #include "XPCLog.h"
 #include "xpccomponents.h"
 #include "xpcexception.h"
@@ -1171,16 +1172,24 @@ public:
 protected:
     virtual ~XPCWrappedNativeScope();
 
     static void KillDyingScopes();
 
     XPCWrappedNativeScope(); // not implemented
 
 private:
+    class ClearInterpositionsObserver MOZ_FINAL : public nsIObserver {
+        ~ClearInterpositionsObserver() {}
+
+      public:
+        NS_DECL_ISUPPORTS
+        NS_DECL_NSIOBSERVER
+    };
+
     static XPCWrappedNativeScope* gScopes;
     static XPCWrappedNativeScope* gDyingScopes;
 
     static InterpositionMap*         gInterpositionMap;
 
     XPCJSRuntime*                    mRuntime;
     Native2WrappedNativeMap*         mWrappedNativeMap;
     ClassInfo2WrappedNativeProtoMap* mWrappedNativeProtoMap;