Bug 1409249: Require singleton constructors to return explicit already_AddRefed. r?froydnj draft
authorKris Maglione <maglione.k@gmail.com>
Mon, 16 Oct 2017 21:08:42 -0700
changeset 681167 ff323852653709c7839f71b5b64594f638ba8aab
parent 681108 8ded456b65770dcfa0e4fc7d63d81a826d50702d
child 736110 1cf45b039b185e2cbb096567cf65982eb2e160af
push id84785
push usermaglione.k@gmail.com
push dateTue, 17 Oct 2017 04:13:07 +0000
reviewersfroydnj
bugs1409249
milestone58.0a1
Bug 1409249: Require singleton constructors to return explicit already_AddRefed. r?froydnj Right now, NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR expects singleton constructors to return already-addrefed raw pointers, and while it accepts constructors that return already_AddRefed, most existing don't do so. Meanwhile, the convention elsewhere is that a raw pointer return value is owned by the callee, and that the caller needs to addref it if it wants to keep its own reference to it. The difference in convention makes it easy to leak (I've definitely caused more than one shutdown leak this way), so it would be better if we required the singleton getters to return an explicit already_AddRefed, which would behave the same for all callers. This also cleans up several singleton constructors that left a dangling pointer to their singletons when their initialization methods failed, when they released their references without clearing their global raw pointers. MozReview-Commit-ID: 9peyG4pRYcr
caps/nsScriptSecurityManager.cpp
caps/nsScriptSecurityManager.h
dom/base/DOMRequest.h
dom/quota/QuotaManagerService.cpp
dom/quota/QuotaManagerService.h
extensions/cookie/nsPermissionManager.cpp
extensions/cookie/nsPermissionManager.h
js/xpconnect/src/nsXPConnect.cpp
js/xpconnect/src/xpcprivate.h
modules/libjar/nsJARProtocolHandler.cpp
modules/libjar/nsJARProtocolHandler.h
modules/libpref/Preferences.cpp
modules/libpref/Preferences.h
netwerk/base/nsIOService.cpp
netwerk/base/nsIOService.h
netwerk/dns/ChildDNSService.cpp
netwerk/dns/ChildDNSService.h
netwerk/dns/nsDNSService2.cpp
netwerk/dns/nsDNSService2.h
startupcache/StartupCache.cpp
startupcache/StartupCache.h
storage/VacuumManager.cpp
storage/VacuumManager.h
storage/mozStorageService.cpp
storage/mozStorageService.h
toolkit/components/downloads/ApplicationReputation.cpp
toolkit/components/downloads/ApplicationReputation.h
toolkit/components/downloads/nsDownloadManager.cpp
toolkit/components/downloads/nsDownloadManager.h
toolkit/components/places/History.cpp
toolkit/components/places/History.h
toolkit/mozapps/extensions/AddonPathService.cpp
toolkit/mozapps/extensions/AddonPathService.h
uriloader/prefetch/nsOfflineCacheUpdate.h
uriloader/prefetch/nsOfflineCacheUpdateService.cpp
xpcom/components/ModuleUtils.h
--- a/caps/nsScriptSecurityManager.cpp
+++ b/caps/nsScriptSecurityManager.cpp
@@ -1494,23 +1494,22 @@ nsScriptSecurityManager::InitStatics()
 
     ClearOnShutdown(&gScriptSecMan);
     gScriptSecMan = ssManager;
 }
 
 // Currently this nsGenericFactory constructor is used only from FastLoad
 // (XPCOM object deserialization) code, when "creating" the system principal
 // singleton.
-SystemPrincipal *
+already_AddRefed<SystemPrincipal>
 nsScriptSecurityManager::SystemPrincipalSingletonConstructor()
 {
-    nsIPrincipal *sysprin = nullptr;
     if (gScriptSecMan)
-        NS_ADDREF(sysprin = gScriptSecMan->mSystemPrincipal);
-    return static_cast<SystemPrincipal*>(sysprin);
+        return do_AddRef(gScriptSecMan->mSystemPrincipal.get()).downcast<SystemPrincipal>();
+    return nullptr;
 }
 
 struct IsWhitespace {
     static bool Test(char aChar) { return NS_IsAsciiWhitespace(aChar); };
 };
 struct IsWhitespaceOrComma {
     static bool Test(char aChar) { return aChar == ',' || NS_IsAsciiWhitespace(aChar); };
 };
--- a/caps/nsScriptSecurityManager.h
+++ b/caps/nsScriptSecurityManager.h
@@ -48,17 +48,17 @@ public:
     NS_DECL_NSIOBSERVER
 
     static nsScriptSecurityManager*
     GetScriptSecurityManager();
 
     // Invoked exactly once, by XPConnect.
     static void InitStatics();
 
-    static SystemPrincipal*
+    static already_AddRefed<SystemPrincipal>
     SystemPrincipalSingletonConstructor();
 
     /**
      * Utility method for comparing two URIs.  For security purposes, two URIs
      * are equivalent if their schemes, hosts, and ports (if any) match.  This
      * method returns true if aSubjectURI and aObjectURI have the same origin,
      * false otherwise.
      */
--- a/dom/base/DOMRequest.h
+++ b/dom/base/DOMRequest.h
@@ -98,22 +98,20 @@ protected:
 class DOMRequestService final : public nsIDOMRequestService
 {
   ~DOMRequestService() {}
 
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOMREQUESTSERVICE
 
-  // Returns an owning reference! No one should call this but the factory.
-  static DOMRequestService* FactoryCreate()
+  // No one should call this but the factory.
+  static already_AddRefed<DOMRequestService> FactoryCreate()
   {
-    DOMRequestService* res = new DOMRequestService;
-    NS_ADDREF(res);
-    return res;
+    return MakeAndAddRef<DOMRequestService>();
   }
 };
 
 } // namespace dom
 } // namespace mozilla
 
 #define DOMREQUEST_SERVICE_CONTRACTID "@mozilla.org/dom/dom-request-service;1"
 
--- a/dom/quota/QuotaManagerService.cpp
+++ b/dom/quota/QuotaManagerService.cpp
@@ -243,24 +243,21 @@ QuotaManagerService::GetOrCreate()
 QuotaManagerService*
 QuotaManagerService::Get()
 {
   // Does not return an owning reference.
   return gQuotaManagerService;
 }
 
 // static
-QuotaManagerService*
+already_AddRefed<QuotaManagerService>
 QuotaManagerService::FactoryCreate()
 {
-  // Returns a raw pointer that carries an owning reference! Lame, but the
-  // singleton factory macros force this.
-  QuotaManagerService* quotaManagerService = GetOrCreate();
-  NS_IF_ADDREF(quotaManagerService);
-  return quotaManagerService;
+  RefPtr<QuotaManagerService> quotaManagerService = GetOrCreate();
+  return quotaManagerService.forget();
 }
 
 void
 QuotaManagerService::ClearBackgroundActor()
 {
   MOZ_ASSERT(NS_IsMainThread());
 
   mBackgroundActor = nullptr;
--- a/dom/quota/QuotaManagerService.h
+++ b/dom/quota/QuotaManagerService.h
@@ -60,18 +60,18 @@ public:
   // Returns a non-owning reference.
   static QuotaManagerService*
   GetOrCreate();
 
   // Returns a non-owning reference.
   static QuotaManagerService*
   Get();
 
-  // Returns an owning reference! No one should call this but the factory.
-  static QuotaManagerService*
+  // No one should call this but the factory.
+  static already_AddRefed<QuotaManagerService>
   FactoryCreate();
 
   void
   ClearBackgroundActor();
 
   void
   NoteLiveManager(QuotaManager* aManager);
 
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -896,39 +896,36 @@ nsPermissionManager::~nsPermissionManage
   }
   mPermissionKeyPromiseMap.Clear();
 
   RemoveAllFromMemory();
   gPermissionManager = nullptr;
 }
 
 // static
-nsIPermissionManager*
+already_AddRefed<nsIPermissionManager>
 nsPermissionManager::GetXPCOMSingleton()
 {
   if (gPermissionManager) {
-    NS_ADDREF(gPermissionManager);
-    return gPermissionManager;
+    return do_AddRef(gPermissionManager);
   }
 
   // Create a new singleton nsPermissionManager.
   // We AddRef only once since XPCOM has rules about the ordering of module
   // teardowns - by the time our module destructor is called, it's too late to
   // Release our members, since GC cycles have already been completed and
   // would result in serious leaks.
   // See bug 209571.
-  gPermissionManager = new nsPermissionManager();
-  if (gPermissionManager) {
-    NS_ADDREF(gPermissionManager);
-    if (NS_FAILED(gPermissionManager->Init())) {
-      NS_RELEASE(gPermissionManager);
-    }
+  auto permManager = MakeRefPtr<nsPermissionManager>();
+  if (permManager && NS_SUCCEEDED(permManager->Init())) {
+    gPermissionManager = permManager.get();
+    return permManager.forget();
   }
 
-  return gPermissionManager;
+  return nullptr;;
 }
 
 nsresult
 nsPermissionManager::Init()
 {
   // If the 'permissions.memory_only' pref is set to true, then don't write any
   // permission settings to disk, but keep them in a memory-only database.
   mMemoryOnlyDB = mozilla::Preferences::GetBool("permissions.memory_only", false);
--- a/extensions/cookie/nsPermissionManager.h
+++ b/extensions/cookie/nsPermissionManager.h
@@ -161,17 +161,17 @@ public:
   };
 
   // nsISupports
   NS_DECL_ISUPPORTS
   NS_DECL_NSIPERMISSIONMANAGER
   NS_DECL_NSIOBSERVER
 
   nsPermissionManager();
-  static nsIPermissionManager* GetXPCOMSingleton();
+  static already_AddRefed<nsIPermissionManager> GetXPCOMSingleton();
   nsresult Init();
 
   // enums for AddInternal()
   enum OperationType {
     eOperationNone,
     eOperationAdding,
     eOperationRemoving,
     eOperationChanging,
--- a/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -136,22 +136,20 @@ nsXPConnect::InitStatics()
         MOZ_CRASH("InitSelfHostedCode failed");
     if (!gSelf->mRuntime->InitializeStrings(cx))
         MOZ_CRASH("InitializeStrings failed");
 
     // Initialize our singleton scopes.
     gSelf->mRuntime->InitSingletonScopes();
 }
 
-nsXPConnect*
+already_AddRefed<nsXPConnect>
 nsXPConnect::GetSingleton()
 {
-    nsXPConnect* xpc = nsXPConnect::XPConnect();
-    NS_IF_ADDREF(xpc);
-    return xpc;
+    return do_AddRef(nsXPConnect::XPConnect());
 }
 
 // static
 void
 nsXPConnect::ReleaseXPConnectSingleton()
 {
     nsXPConnect* xpc = gSelf;
     if (xpc) {
--- a/js/xpconnect/src/xpcprivate.h
+++ b/js/xpconnect/src/xpcprivate.h
@@ -258,20 +258,17 @@ public:
 
     static nsIPrincipal* SystemPrincipal()
     {
         MOZ_ASSERT(NS_IsMainThread());
         MOZ_ASSERT(gSystemPrincipal);
         return gSystemPrincipal;
     }
 
-    // This returns an AddRef'd pointer. It does not do this with an 'out' param
-    // only because this form is required by the generic module macro:
-    // NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR
-    static nsXPConnect* GetSingleton();
+    static already_AddRefed<nsXPConnect> GetSingleton();
 
     // Called by module code in dll startup
     static void InitStatics();
     // Called by module code on dll shutdown.
     static void ReleaseXPConnectSingleton();
 
     bool IsShuttingDown() const {return mShuttingDown;}
 
--- a/modules/libjar/nsJARProtocolHandler.cpp
+++ b/modules/libjar/nsJARProtocolHandler.cpp
@@ -58,33 +58,29 @@ nsJARProtocolHandler::MimeService()
     return mMimeService.get();
 }
 
 NS_IMPL_ISUPPORTS(nsJARProtocolHandler,
                   nsIJARProtocolHandler,
                   nsIProtocolHandler,
                   nsISupportsWeakReference)
 
-nsJARProtocolHandler*
+already_AddRefed<nsJARProtocolHandler>
 nsJARProtocolHandler::GetSingleton()
 {
     if (!gJarHandler) {
-        gJarHandler = new nsJARProtocolHandler();
-        if (!gJarHandler)
-            return nullptr;
-
-        NS_ADDREF(gJarHandler);
-        nsresult rv = gJarHandler->Init();
-        if (NS_FAILED(rv)) {
-            NS_RELEASE(gJarHandler);
+        auto jar = MakeRefPtr<nsJARProtocolHandler>();
+        gJarHandler = jar.get();
+        if (!jar || NS_FAILED(jar->Init())) {
+            gJarHandler = nullptr;
             return nullptr;
         }
+        return jar.forget();
     }
-    NS_ADDREF(gJarHandler);
-    return gJarHandler;
+    return do_AddRef(gJarHandler);
 }
 
 NS_IMETHODIMP
 nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result)
 {
     *result = mJARCache;
     NS_ADDREF(*result);
     return NS_OK;
--- a/modules/libjar/nsJARProtocolHandler.h
+++ b/modules/libjar/nsJARProtocolHandler.h
@@ -20,17 +20,17 @@ class nsJARProtocolHandler final : publi
 public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSIPROTOCOLHANDLER
     NS_DECL_NSIJARPROTOCOLHANDLER
 
     // nsJARProtocolHandler methods:
     nsJARProtocolHandler();
 
-    static nsJARProtocolHandler *GetSingleton();
+    static already_AddRefed<nsJARProtocolHandler> GetSingleton();
 
     nsresult Init();
 
     // returns non addref'ed pointer.
     nsIMIMEService    *MimeService();
     nsIZipReaderCache *JarCache() { return mJARCache; }
 protected:
     virtual ~nsJARProtocolHandler();
--- a/modules/libpref/Preferences.cpp
+++ b/modules/libpref/Preferences.cpp
@@ -3886,22 +3886,21 @@ public:
   NS_IMETHOD Run() override
   {
     return RegisterStrongMemoryReporter(new PreferenceServiceReporter());
   }
 };
 
 } // namespace
 
-/* static */ Preferences*
+/* static */ already_AddRefed<Preferences>
 Preferences::GetInstanceForService()
 {
   if (sPreferences) {
-    NS_ADDREF(sPreferences);
-    return sPreferences;
+    return do_AddRef(sPreferences);
   }
 
   if (sShutdown) {
     gCacheDataDesc = "shutting down in GetInstanceForService()";
     return nullptr;
   }
 
   sRootBranch = new nsPrefBranch("", false);
@@ -3912,34 +3911,34 @@ Preferences::GetInstanceForService()
   sPreferences = new Preferences();
   NS_ADDREF(sPreferences);
 
   Result<Ok, const char*> res = sPreferences->Init();
   if (res.isErr()) {
     // The singleton instance will delete sRootBranch and sDefaultRootBranch.
     gCacheDataDesc = res.unwrapErr();
     NS_RELEASE(sPreferences);
+    sPreferences = nullptr;
     return nullptr;
   }
 
   gCacheData = new nsTArray<nsAutoPtr<CacheData>>();
   gCacheDataDesc = "set by GetInstanceForService()";
 
   gObserverTable = new nsRefPtrHashtable<ValueObserverHashKey, ValueObserver>();
 
   // Preferences::GetInstanceForService() can be called from GetService(), and
   // RegisterStrongMemoryReporter calls GetService(nsIMemoryReporter).  To
   // avoid a potential recursive GetService() call, we can't register the
   // memory reporter here; instead, do it off a runnable.
   RefPtr<AddPreferencesMemoryReporterRunnable> runnable =
     new AddPreferencesMemoryReporterRunnable();
   NS_DispatchToMainThread(runnable);
 
-  NS_ADDREF(sPreferences);
-  return sPreferences;
+  return do_AddRef(sPreferences);
 }
 
 /* static */ bool
 Preferences::IsServiceAvailable()
 {
   return !!sPreferences;
 }
 
--- a/modules/libpref/Preferences.h
+++ b/modules/libpref/Preferences.h
@@ -73,17 +73,17 @@ public:
 
   // Returns true if the Preferences service is available, false otherwise.
   static bool IsServiceAvailable();
 
   // Initialize user prefs from prefs.js/user.js
   static void InitializeUserPrefs();
 
   // Returns the singleton instance which is addreffed.
-  static Preferences* GetInstanceForService();
+  static already_AddRefed<Preferences> GetInstanceForService();
 
   // Finallizes global members.
   static void Shutdown();
 
   // Returns shared pref service instance NOTE: not addreffed.
   static nsIPrefService* GetService()
   {
     NS_ENSURE_TRUE(InitStaticMembers(), nullptr);
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -346,33 +346,29 @@ nsIOService::InitializeProtocolProxyServ
     if (XRE_IsParentProcess()) {
         // for early-initialization
         Unused << do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID, &rv);
     }
 
     return rv;
 }
 
-nsIOService*
+already_AddRefed<nsIOService>
 nsIOService::GetInstance() {
     if (!gIOService) {
-        gIOService = new nsIOService();
-        if (!gIOService)
-            return nullptr;
-        NS_ADDREF(gIOService);
-
-        nsresult rv = gIOService->Init();
-        if (NS_FAILED(rv)) {
-            NS_RELEASE(gIOService);
+        RefPtr<nsIOService> ios = new nsIOService();
+        gIOService = ios.get();
+        if (!ios || NS_FAILED(ios->Init())) {
+            gIOService = nullptr;
             return nullptr;
         }
-        return gIOService;
+
+        return ios.forget();
     }
-    NS_ADDREF(gIOService);
-    return gIOService;
+    return do_AddRef(gIOService);
 }
 
 NS_IMPL_ISUPPORTS(nsIOService,
                   nsIIOService,
                   nsIIOService2,
                   nsINetUtil,
                   nsISpeculativeConnect,
                   nsIObserver,
--- a/netwerk/base/nsIOService.h
+++ b/netwerk/base/nsIOService.h
@@ -59,18 +59,17 @@ public:
     NS_DECL_NSIIOSERVICE2
     NS_DECL_NSIOBSERVER
     NS_DECL_NSINETUTIL
     NS_DECL_NSISPECULATIVECONNECT
     NS_DECL_NSIIOSERVICEINTERNAL
 
     // Gets the singleton instance of the IO Service, creating it as needed
     // Returns nullptr on out of memory or failure to initialize.
-    // Returns an addrefed pointer.
-    static nsIOService* GetInstance();
+    static already_AddRefed<nsIOService> GetInstance();
 
     nsresult Init();
     nsresult NewURI(const char* aSpec, nsIURI* aBaseURI,
                                 nsIURI* *result,
                                 nsIProtocolHandler* *hdlrResult);
 
     // Called by channels before a redirect happens. This notifies the global
     // redirect observers.
--- a/netwerk/dns/ChildDNSService.cpp
+++ b/netwerk/dns/ChildDNSService.cpp
@@ -21,26 +21,25 @@ namespace net {
 
 //-----------------------------------------------------------------------------
 // ChildDNSService
 //-----------------------------------------------------------------------------
 
 static ChildDNSService *gChildDNSService;
 static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch";
 
-ChildDNSService* ChildDNSService::GetSingleton()
+already_AddRefed<ChildDNSService> ChildDNSService::GetSingleton()
 {
   MOZ_ASSERT(IsNeckoChild());
 
   if (!gChildDNSService) {
     gChildDNSService = new ChildDNSService();
   }
 
-  NS_ADDREF(gChildDNSService);
-  return gChildDNSService;
+  return do_AddRef(gChildDNSService);
 }
 
 NS_IMPL_ISUPPORTS(ChildDNSService,
                   nsIDNSService,
                   nsPIDNSService,
                   nsIObserver)
 
 ChildDNSService::ChildDNSService()
--- a/netwerk/dns/ChildDNSService.h
+++ b/netwerk/dns/ChildDNSService.h
@@ -27,17 +27,17 @@ public:
   // AsyncResolve (and CancelAsyncResolve) can be called off-main
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSPIDNSSERVICE
   NS_DECL_NSIDNSSERVICE
   NS_DECL_NSIOBSERVER
 
   ChildDNSService();
 
-  static ChildDNSService* GetSingleton();
+  static already_AddRefed<ChildDNSService> GetSingleton();
 
   void NotifyRequestDone(DNSRequestChild *aDnsRequest);
 
   bool GetOffline() const;
 private:
   virtual ~ChildDNSService();
 
   void MOZ_ALWAYS_INLINE GetDNSRecordHashKey(const nsACString &aHost,
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -494,45 +494,43 @@ NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSSe
                   nsIMemoryReporter)
 
 /******************************************************************************
  * nsDNSService impl:
  * singleton instance ctor/dtor methods
  ******************************************************************************/
 static nsDNSService *gDNSService;
 
-nsIDNSService*
+already_AddRefed<nsIDNSService>
 nsDNSService::GetXPCOMSingleton()
 {
     if (IsNeckoChild()) {
         return ChildDNSService::GetSingleton();
     }
 
     return GetSingleton();
 }
 
-nsDNSService*
+already_AddRefed<nsDNSService>
 nsDNSService::GetSingleton()
 {
     NS_ASSERTION(!IsNeckoChild(), "not a parent process");
 
     if (gDNSService) {
-        NS_ADDREF(gDNSService);
-        return gDNSService;
+        return do_AddRef(gDNSService);
     }
 
-    gDNSService = new nsDNSService();
-    if (gDNSService) {
-        NS_ADDREF(gDNSService);
-        if (NS_FAILED(gDNSService->Init())) {
-              NS_RELEASE(gDNSService);
-        }
+    auto dns = MakeRefPtr<nsDNSService>();
+    gDNSService = dns.get();
+    if (!dns || NS_FAILED(dns->Init())) {
+        gDNSService = nullptr;
+        return nullptr;
     }
 
-    return gDNSService;
+    return dns.forget();
 }
 
 NS_IMETHODIMP
 nsDNSService::Init()
 {
     if (mResolver)
         return NS_OK;
     NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
--- a/netwerk/dns/nsDNSService2.h
+++ b/netwerk/dns/nsDNSService2.h
@@ -29,34 +29,34 @@ public:
     NS_DECL_THREADSAFE_ISUPPORTS
     NS_DECL_NSPIDNSSERVICE
     NS_DECL_NSIDNSSERVICE
     NS_DECL_NSIOBSERVER
     NS_DECL_NSIMEMORYREPORTER
 
     nsDNSService();
 
-    static nsIDNSService* GetXPCOMSingleton();
+    static already_AddRefed<nsIDNSService> GetXPCOMSingleton();
 
     size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const;
 
     bool GetOffline() const;
 
 protected:
     friend class nsAuthSSPI;
 
     nsresult DeprecatedSyncResolve(const nsACString &aHostname,
                                    uint32_t flags,
                                    const mozilla::OriginAttributes &aOriginAttributes,
                                    nsIDNSRecord **result);
 
 private:
     ~nsDNSService();
 
-    static nsDNSService* GetSingleton();
+    static already_AddRefed<nsDNSService> GetSingleton();
 
     uint16_t GetAFForLookup(const nsACString &host, uint32_t flags);
 
     nsresult PreprocessHostname(bool              aLocalDomain,
                                 const nsACString &aInput,
                                 nsIIDNService    *aIDN,
                                 nsACString       &aACE);
 
--- a/startupcache/StartupCache.cpp
+++ b/startupcache/StartupCache.cpp
@@ -695,23 +695,22 @@ StartupCacheDebugOutputStream::PutBuffer
   mBinaryStream->PutBuffer(aBuffer, aLength);
 }
 #endif //DEBUG
 
 StartupCacheWrapper* StartupCacheWrapper::gStartupCacheWrapper = nullptr;
 
 NS_IMPL_ISUPPORTS(StartupCacheWrapper, nsIStartupCache)
 
-StartupCacheWrapper* StartupCacheWrapper::GetSingleton()
+already_AddRefed<StartupCacheWrapper> StartupCacheWrapper::GetSingleton()
 {
   if (!gStartupCacheWrapper)
     gStartupCacheWrapper = new StartupCacheWrapper();
 
-  NS_ADDREF(gStartupCacheWrapper);
-  return gStartupCacheWrapper;
+  return do_AddRef(gStartupCacheWrapper);
 }
 
 nsresult
 StartupCacheWrapper::GetBuffer(const char* id, char** outbuf, uint32_t* length)
 {
   StartupCache* sc = StartupCache::GetSingleton();
   if (!sc) {
     return NS_ERROR_NOT_INITIALIZED;
--- a/startupcache/StartupCache.h
+++ b/startupcache/StartupCache.h
@@ -209,16 +209,16 @@ class StartupCacheDebugOutputStream fina
 class StartupCacheWrapper final
   : public nsIStartupCache
 {
   ~StartupCacheWrapper() {}
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSISTARTUPCACHE
 
-  static StartupCacheWrapper* GetSingleton();
+  static already_AddRefed<StartupCacheWrapper> GetSingleton();
   static StartupCacheWrapper *gStartupCacheWrapper;
 };
 
 } // namespace scache
 } // namespace mozilla
 
 #endif //StartupCache_h_
--- a/storage/VacuumManager.cpp
+++ b/storage/VacuumManager.cpp
@@ -306,33 +306,28 @@ Vacuumer::notifyCompletion(bool aSucceed
 NS_IMPL_ISUPPORTS(
   VacuumManager
 , nsIObserver
 )
 
 VacuumManager *
 VacuumManager::gVacuumManager = nullptr;
 
-VacuumManager *
+already_AddRefed<VacuumManager>
 VacuumManager::getSingleton()
 {
   //Don't allocate it in the child Process.
   if (!XRE_IsParentProcess()) {
     return nullptr;
   }
 
-  if (gVacuumManager) {
-    NS_ADDREF(gVacuumManager);
-    return gVacuumManager;
+  if (!gVacuumManager) {
+    gVacuumManager = new VacuumManager();
   }
-  gVacuumManager = new VacuumManager();
-  if (gVacuumManager) {
-    NS_ADDREF(gVacuumManager);
-  }
-  return gVacuumManager;
+  return do_AddRef(gVacuumManager);
 }
 
 VacuumManager::VacuumManager()
   : mParticipants("vacuum-participant")
 {
   MOZ_ASSERT(!gVacuumManager,
              "Attempting to create two instances of the service!");
   gVacuumManager = this;
--- a/storage/VacuumManager.h
+++ b/storage/VacuumManager.h
@@ -23,17 +23,17 @@ public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 
   VacuumManager();
 
   /**
    * Obtains the VacuumManager object.
    */
-  static VacuumManager * getSingleton();
+  static already_AddRefed<VacuumManager> getSingleton();
 
 private:
   ~VacuumManager();
 
   static VacuumManager *gVacuumManager;
 
   // Cache of components registered in "vacuum-participant" category.
   nsCategoryCache<mozIStorageVacuumParticipant> mParticipants;
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -184,22 +184,21 @@ NS_IMPL_ISUPPORTS(
   Service,
   mozIStorageService,
   nsIObserver,
   nsIMemoryReporter
 )
 
 Service *Service::gService = nullptr;
 
-Service *
+already_AddRefed<Service>
 Service::getSingleton()
 {
   if (gService) {
-    NS_ADDREF(gService);
-    return gService;
+    return do_AddRef(gService);
   }
 
   // Ensure that we are using the same version of SQLite that we compiled with
   // or newer.  Our configure check ensures we are using a new enough version
   // at compile time.
   if (SQLITE_VERSION_NUMBER > ::sqlite3_libversion_number()) {
     nsCOMPtr<nsIPromptService> ps(do_GetService(NS_PROMPTSERVICE_CONTRACTID));
     if (ps) {
@@ -213,24 +212,24 @@ Service::getSingleton()
       (void)ps->Alert(nullptr, title.get(), message.get());
     }
     MOZ_CRASH("SQLite Version Error");
   }
 
   // The first reference to the storage service must be obtained on the
   // main thread.
   NS_ENSURE_TRUE(NS_IsMainThread(), nullptr);
-  gService = new Service();
-  if (gService) {
-    NS_ADDREF(gService);
-    if (NS_FAILED(gService->initialize()))
-      NS_RELEASE(gService);
+  RefPtr<Service> service = new Service();
+  gService = service.get();
+  if (!service || NS_FAILED(service->initialize())) {
+    gService = nullptr;
+    return nullptr;
   }
 
-  return gService;
+  return service.forget();
 }
 
 nsIXPConnect *Service::sXPConnect = nullptr;
 
 // static
 already_AddRefed<nsIXPConnect>
 Service::getXPConnect()
 {
--- a/storage/mozStorageService.h
+++ b/storage/mozStorageService.h
@@ -47,17 +47,17 @@ public:
    * @return aStr1 - aStr2.  That is, if aStr1 < aStr2, returns a negative
    *         number.  If aStr1 > aStr2, returns a positive number.  If
    *         aStr1 == aStr2, returns 0.
    */
   int localeCompareStrings(const nsAString &aStr1,
                            const nsAString &aStr2,
                            int32_t aComparisonStrength);
 
-  static Service *getSingleton();
+  static already_AddRefed<Service> getSingleton();
 
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_MOZISTORAGESERVICE
   NS_DECL_NSIOBSERVER
   NS_DECL_NSIMEMORYREPORTER
 
   /**
    * Obtains an already AddRefed pointer to XPConnect.  This is used by
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -1547,31 +1547,23 @@ PendingLookup::OnStopRequestInternal(nsI
 }
 
 NS_IMPL_ISUPPORTS(ApplicationReputationService,
                   nsIApplicationReputationService)
 
 ApplicationReputationService*
   ApplicationReputationService::gApplicationReputationService = nullptr;
 
-ApplicationReputationService*
+already_AddRefed<ApplicationReputationService>
 ApplicationReputationService::GetSingleton()
 {
-  if (gApplicationReputationService) {
-    NS_ADDREF(gApplicationReputationService);
-    return gApplicationReputationService;
+  if (!gApplicationReputationService) {
+    gApplicationReputationService = new ApplicationReputationService();
   }
-
-  // We're not initialized yet.
-  gApplicationReputationService = new ApplicationReputationService();
-  if (gApplicationReputationService) {
-    NS_ADDREF(gApplicationReputationService);
-  }
-
-  return gApplicationReputationService;
+  return do_AddRef(gApplicationReputationService);
 }
 
 ApplicationReputationService::ApplicationReputationService()
 {
   LOG(("Application reputation service started up"));
 }
 
 ApplicationReputationService::~ApplicationReputationService() {
--- a/toolkit/components/downloads/ApplicationReputation.h
+++ b/toolkit/components/downloads/ApplicationReputation.h
@@ -22,17 +22,17 @@ class PendingLookup;
 
 class ApplicationReputationService final :
   public nsIApplicationReputationService {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIAPPLICATIONREPUTATIONSERVICE
 
 public:
-  static ApplicationReputationService* GetSingleton();
+  static already_AddRefed<ApplicationReputationService> GetSingleton();
 
 private:
   friend class PendingLookup;
   friend class PendingDBLookup;
   /**
    * Global singleton object for holding this factory service.
    */
   static ApplicationReputationService* gApplicationReputationService;
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -20,32 +20,30 @@ using namespace mozilla;
 
 NS_IMPL_ISUPPORTS(
   nsDownloadManager
 , nsIDownloadManager
 )
 
 nsDownloadManager *nsDownloadManager::gDownloadManagerService = nullptr;
 
-nsDownloadManager *
+already_AddRefed<nsDownloadManager>
 nsDownloadManager::GetSingleton()
 {
   if (gDownloadManagerService) {
-    NS_ADDREF(gDownloadManagerService);
-    return gDownloadManagerService;
+    return do_AddRef(gDownloadManagerService);
   }
 
-  gDownloadManagerService = new nsDownloadManager();
-  if (gDownloadManagerService) {
-    NS_ADDREF(gDownloadManagerService);
-    if (NS_FAILED(gDownloadManagerService->Init()))
-      NS_RELEASE(gDownloadManagerService);
+  auto serv = MakeRefPtr<nsDownloadManager>();
+  gDownloadManagerService = serv.get();
+  if (!serv || NS_FAILED(serv->Init())) {
+    gDownloadManagerService = serv.get();
+    return nullptr;
   }
-
-  return gDownloadManagerService;
+  return serv.forget();
 }
 
 nsDownloadManager::~nsDownloadManager()
 {
   gDownloadManagerService = nullptr;
 }
 
 nsresult
--- a/toolkit/components/downloads/nsDownloadManager.h
+++ b/toolkit/components/downloads/nsDownloadManager.h
@@ -16,17 +16,17 @@
 class nsDownloadManager final : public nsIDownloadManager
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIDOWNLOADMANAGER
 
   nsresult Init();
 
-  static nsDownloadManager *GetSingleton();
+  static already_AddRefed<nsDownloadManager> GetSingleton();
 
   nsDownloadManager()
   {
   }
 
 protected:
   virtual ~nsDownloadManager();
 
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -2416,27 +2416,26 @@ History::GetService()
   if (service) {
     NS_ASSERTION(gService, "Our constructor was not run?!");
   }
 
   return gService;
 }
 
 /* static */
-History*
+already_AddRefed<History>
 History::GetSingleton()
 {
   if (!gService) {
     gService = new History();
     NS_ENSURE_TRUE(gService, nullptr);
     gService->InitMemoryReporter();
   }
 
-  NS_ADDREF(gService);
-  return gService;
+  return do_AddRef(gService);
 }
 
 mozIStorageConnection*
 History::GetDBConn()
 {
   MOZ_ASSERT(NS_IsMainThread());
   if (mShuttingDown)
     return nullptr;
--- a/toolkit/components/places/History.h
+++ b/toolkit/components/places/History.h
@@ -102,20 +102,19 @@ public:
   size_t SizeOfIncludingThis(mozilla::MallocSizeOf aMallocSizeOf);
 
   /**
    * Obtains a pointer to this service.
    */
   static History* GetService();
 
   /**
-   * Obtains a pointer that has had AddRef called on it.  Used by the service
-   * manager only.
+   * Used by the service manager only.
    */
-  static History* GetSingleton();
+  static already_AddRefed<History> GetSingleton();
 
   template<int N>
   already_AddRefed<mozIStorageStatement>
   GetStatement(const char (&aQuery)[N])
   {
     // May be invoked on both threads.
     const mozIStorageConnection* dbConn = GetConstDBConn();
     NS_ENSURE_TRUE(dbConn, nullptr);
--- a/toolkit/mozapps/extensions/AddonPathService.cpp
+++ b/toolkit/mozapps/extensions/AddonPathService.cpp
@@ -52,24 +52,23 @@ AddonPathService::~AddonPathService()
 {
   sInstance = nullptr;
 }
 
 NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService)
 
 AddonPathService *AddonPathService::sInstance;
 
-/* static */ AddonPathService*
+/* static */ already_AddRefed<AddonPathService>
 AddonPathService::GetInstance()
 {
   if (!sInstance) {
     sInstance = new AddonPathService();
   }
-  NS_ADDREF(sInstance);
-  return sInstance;
+  return do_AddRef(sInstance);
 }
 
 static JSAddonId*
 ConvertAddonId(const nsAString& addonIdString)
 {
   AutoSafeJSContext cx;
   JS::RootedValue strv(cx);
   if (!mozilla::dom::ToJSValue(cx, addonIdString, &strv)) {
--- a/toolkit/mozapps/extensions/AddonPathService.h
+++ b/toolkit/mozapps/extensions/AddonPathService.h
@@ -18,17 +18,17 @@ namespace mozilla {
 JSAddonId*
 MapURIToAddonID(nsIURI* aURI);
 
 class AddonPathService final : public amIAddonPathService
 {
 public:
   AddonPathService();
 
-  static AddonPathService* GetInstance();
+  static already_AddRefed<AddonPathService> GetInstance();
 
   JSAddonId* Find(const nsAString& path);
   static JSAddonId* FindAddonId(const nsAString& path);
 
   NS_DECL_ISUPPORTS
   NS_DECL_AMIADDONPATHSERVICE
 
   struct PathEntry
--- a/uriloader/prefetch/nsOfflineCacheUpdate.h
+++ b/uriloader/prefetch/nsOfflineCacheUpdate.h
@@ -351,18 +351,17 @@ public:
     virtual nsresult UpdateFinished(nsOfflineCacheUpdate *aUpdate) override;
 
     /**
      * Returns the singleton nsOfflineCacheUpdateService without an addref, or
      * nullptr if the service couldn't be created.
      */
     static nsOfflineCacheUpdateService *EnsureService();
 
-    /** Addrefs and returns the singleton nsOfflineCacheUpdateService. */
-    static nsOfflineCacheUpdateService *GetInstance();
+    static already_AddRefed<nsOfflineCacheUpdateService> GetInstance();
 
     static nsresult OfflineAppPinnedForURI(nsIURI *aDocumentURI,
                                            nsIPrefBranch *aPrefBranch,
                                            bool *aPinned);
 
     static nsTHashtable<nsCStringHashKey>* AllowedDomains();
 
 private:
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -287,35 +287,30 @@ nsOfflineCacheUpdateService::Init()
     NS_ENSURE_SUCCESS(rv, rv);
 
     gOfflineCacheUpdateService = this;
 
     return NS_OK;
 }
 
 /* static */
-nsOfflineCacheUpdateService *
+already_AddRefed<nsOfflineCacheUpdateService>
 nsOfflineCacheUpdateService::GetInstance()
 {
     if (!gOfflineCacheUpdateService) {
-        gOfflineCacheUpdateService = new nsOfflineCacheUpdateService();
-        if (!gOfflineCacheUpdateService)
-            return nullptr;
-        NS_ADDREF(gOfflineCacheUpdateService);
-        nsresult rv = gOfflineCacheUpdateService->Init();
-        if (NS_FAILED(rv)) {
-            NS_RELEASE(gOfflineCacheUpdateService);
+        auto serv = MakeRefPtr<nsOfflineCacheUpdateService>();
+        gOfflineCacheUpdateService = serv.get();
+        if (!serv || NS_FAILED(serv->Init())) {
+            gOfflineCacheUpdateService = nullptr;
             return nullptr;
         }
-        return gOfflineCacheUpdateService;
+        return serv.forget();
     }
 
-    NS_ADDREF(gOfflineCacheUpdateService);
-
-    return gOfflineCacheUpdateService;
+    return do_AddRef(gOfflineCacheUpdateService);
 }
 
 /* static */
 nsOfflineCacheUpdateService *
 nsOfflineCacheUpdateService::EnsureService()
 {
     if (!gOfflineCacheUpdateService) {
         // Make the service manager hold a long-lived reference to the service
--- a/xpcom/components/ModuleUtils.h
+++ b/xpcom/components/ModuleUtils.h
@@ -44,30 +44,52 @@ static nsresult                         
   rv = inst->_InitMethod();                                                   \
   if (NS_SUCCEEDED(rv)) {                                                     \
     rv = inst->QueryInterface(aIID, aResult);                                 \
   }                                                                           \
                                                                               \
   return rv;                                                                  \
 }
 
+namespace mozilla {
+namespace detail {
+
+template<typename T>
+struct RemoveAlreadyAddRefed
+{
+  using Type = T;
+};
+
+template<typename T>
+struct RemoveAlreadyAddRefed<already_AddRefed<T>>
+{
+  using Type = T;
+};
+
+} // namespace detail
+} // namespace mozilla
+
 // 'Constructor' that uses an existing getter function that gets a singleton.
-// NOTE: assumes that getter does an AddRef - so additional AddRef is not done.
 #define NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(_InstanceClass, _GetterProc) \
 static nsresult                                                               \
 _InstanceClass##Constructor(nsISupports *aOuter, REFNSIID aIID,               \
                             void **aResult)                                   \
 {                                                                             \
   RefPtr<_InstanceClass> inst;                                                \
                                                                               \
   *aResult = nullptr;                                                         \
   if (nullptr != aOuter) {                                                    \
     return NS_ERROR_NO_AGGREGATION;                                           \
   }                                                                           \
                                                                               \
-  inst = already_AddRefed<_InstanceClass>(_GetterProc());                     \
+  using T = mozilla::detail::RemoveAlreadyAddRefed<decltype(_GetterProc())>::Type; \
+  static_assert(mozilla::IsSame<already_AddRefed<T>, decltype(_GetterProc())>::value, \
+               "Singleton constructor must return already_AddRefed");         \
+  static_assert(mozilla::IsBaseOf<_InstanceClass, T>::value,                  \
+               "Singleton constructor must return correct already_AddRefed"); \
+  inst = _GetterProc();                                                       \
   if (nullptr == inst) {                                                      \
     return NS_ERROR_OUT_OF_MEMORY;                                            \
   }                                                                           \
   return inst->QueryInterface(aIID, aResult);                                 \
 }
 
 #endif // mozilla_GenericModule_h