Bug 1412726: Clean up XPCOM singleton constructor refcount handling. r?froydnj
This is a follow-up to
bug 1409249. There are a lot of places where our
factory singleton constructors either don't correctly handle their returned
references being released by the component manager, or do handle it, but in
ways that are not obvious.
This patch handles a few places where we can sometimes wind up with dangling
singleton pointers, adds some explanatory comments and sanity check
assertions, and replaces some uses of manual refcounting with StaticRefPtr and
ClearOnShutdown.
There are still some places where we may wind up with odd behavior if the
first QI for a getService call fails, and we wind up destroying the first
instance of a service that we create, and re-creating a new one later.
MozReview-Commit-ID: ANYndvd7aZx
--- a/dom/flyweb/FlyWebService.cpp
+++ b/dom/flyweb/FlyWebService.cpp
@@ -916,21 +916,22 @@ FlyWebService::GetExisting()
return gFlyWebService;
}
FlyWebService*
FlyWebService::GetOrCreate()
{
if (!gFlyWebService) {
gFlyWebService = new FlyWebService();
- ClearOnShutdown(&gFlyWebService);
ErrorResult rv = gFlyWebService->Init();
- if (rv.Failed()) {
+ if (NS_WARN_IF(rv.Failed())) {
+ rv.SuppressException();
gFlyWebService = nullptr;
- return nullptr;
+ } else {
+ ClearOnShutdown(&gFlyWebService);
}
}
return gFlyWebService;
}
ErrorResult
FlyWebService::Init()
{
--- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
+++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
@@ -11,16 +11,17 @@
#include "MediaPrefs.h"
#include "SpeechSynthesisUtterance.h"
#include "SpeechSynthesisVoice.h"
#include "nsSynthVoiceRegistry.h"
#include "nsSpeechTask.h"
#include "AudioChannelService.h"
#include "nsString.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/StaticPtr.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/intl/LocaleService.h"
#include "mozilla/Unused.h"
#include "SpeechSynthesisChild.h"
#include "SpeechSynthesisParent.h"
@@ -166,16 +167,17 @@ nsSynthVoiceRegistry::~nsSynthVoiceRegis
nsSynthVoiceRegistry*
nsSynthVoiceRegistry::GetInstance()
{
MOZ_ASSERT(NS_IsMainThread());
if (!gSynthVoiceRegistry) {
gSynthVoiceRegistry = new nsSynthVoiceRegistry();
+ ClearOnShutdown(&gSynthVoiceRegistry);
if (XRE_IsParentProcess()) {
// Start up all speech synth services.
NS_CreateServicesFromCategory(NS_SPEECH_SYNTH_STARTED, nullptr,
NS_SPEECH_SYNTH_STARTED);
}
}
return gSynthVoiceRegistry;
@@ -184,24 +186,16 @@ nsSynthVoiceRegistry::GetInstance()
already_AddRefed<nsSynthVoiceRegistry>
nsSynthVoiceRegistry::GetInstanceForService()
{
RefPtr<nsSynthVoiceRegistry> registry = GetInstance();
return registry.forget();
}
-void
-nsSynthVoiceRegistry::Shutdown()
-{
- LOG(LogLevel::Debug, ("[%s] nsSynthVoiceRegistry::Shutdown()",
- (XRE_IsContentProcess()) ? "Content" : "Default"));
- gSynthVoiceRegistry = nullptr;
-}
-
bool
nsSynthVoiceRegistry::SendInitialVoicesAndState(SpeechSynthesisParent* aParent)
{
MOZ_ASSERT(XRE_IsParentProcess());
InfallibleTArray<RemoteVoice> voices;
InfallibleTArray<nsString> defaults;
--- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.h
+++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.h
@@ -63,18 +63,16 @@ public:
static void RecvAddVoice(const RemoteVoice& aVoice);
static void RecvSetDefaultVoice(const nsAString& aUri, bool aIsDefault);
static void RecvIsSpeakingChanged(bool aIsSpeaking);
static void RecvNotifyVoicesChanged();
- static void Shutdown();
-
private:
virtual ~nsSynthVoiceRegistry();
VoiceData* FindBestMatch(const nsAString& aUri, const nsAString& lang);
bool FindVoiceByLang(const nsAString& aLang, VoiceData** aRetval);
nsresult AddVoiceImpl(nsISpeechService* aService,
--- a/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp
+++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherModule.cpp
@@ -32,25 +32,19 @@ static const mozilla::Module::ContractID
{ nullptr }
};
static const mozilla::Module::CategoryEntry kCategories[] = {
{ "speech-synth-started", "SpeechDispatcher Speech Synth", SPEECHDISPATCHERSERVICE_CONTRACTID },
{ nullptr }
};
-static void
-UnloadSpeechDispatcherModule()
-{
- SpeechDispatcherService::Shutdown();
-}
-
static const mozilla::Module kModule = {
mozilla::Module::kVersion,
kCIDs,
kContracts,
kCategories,
nullptr,
nullptr,
- UnloadSpeechDispatcherModule
+ nullptr,
};
NSMODULE_DEFN(synthspeechdispatcher) = &kModule;
--- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp
+++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.cpp
@@ -3,16 +3,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "SpeechDispatcherService.h"
#include "mozilla/dom/nsSpeechTask.h"
#include "mozilla/dom/nsSynthVoiceRegistry.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/Preferences.h"
#include "nsEscape.h"
#include "nsISupports.h"
#include "nsPrintfCString.h"
#include "nsReadableUtils.h"
#include "nsServiceManagerUtils.h"
#include "nsThreadUtils.h"
#include "prlink.h"
@@ -563,16 +564,17 @@ SpeechDispatcherService::GetInstance(boo
MOZ_ASSERT(false,
"SpeechDispatcherService can only be started on main gecko process");
return nullptr;
}
if (!sSingleton && create) {
sSingleton = new SpeechDispatcherService();
sSingleton->Init();
+ ClearOnShutdown(&sSingleton);
}
return sSingleton;
}
already_AddRefed<SpeechDispatcherService>
SpeechDispatcherService::GetInstanceForService()
{
@@ -588,20 +590,10 @@ SpeechDispatcherService::EventNotify(uin
if (callback) {
if (callback->OnSpeechEvent((SPDNotificationType)aState)) {
mCallbacks.Remove(aMsgId);
}
}
}
-void
-SpeechDispatcherService::Shutdown()
-{
- if (!sSingleton) {
- return;
- }
-
- sSingleton = nullptr;
-}
-
} // namespace dom
} // namespace mozilla
--- a/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h
+++ b/dom/media/webspeech/synth/speechd/SpeechDispatcherService.h
@@ -37,18 +37,16 @@ public:
void Setup();
void EventNotify(uint32_t aMsgId, uint32_t aState);
static SpeechDispatcherService* GetInstance(bool create = true);
static already_AddRefed<SpeechDispatcherService> GetInstanceForService();
- static void Shutdown();
-
static StaticRefPtr<SpeechDispatcherService> sSingleton;
private:
virtual ~SpeechDispatcherService();
void RegisterVoices();
bool mInitialized;
--- a/dom/plugins/base/nsPluginHost.cpp
+++ b/dom/plugins/base/nsPluginHost.cpp
@@ -47,16 +47,17 @@
#include "nsVersionComparator.h"
#include "nsIObjectLoadingContent.h"
#include "nsIWritablePropertyBag2.h"
#include "nsICategoryManager.h"
#include "nsPluginStreamListenerPeer.h"
#include "mozilla/dom/ContentChild.h"
#include "mozilla/dom/ContentParent.h"
#include "mozilla/dom/FakePluginTagInitBinding.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/LoadInfo.h"
#include "mozilla/plugins/PluginBridge.h"
#include "mozilla/plugins/PluginTypes.h"
#include "mozilla/Preferences.h"
#include "mozilla/ipc/URIUtils.h"
#include "nsEnumeratorUtils.h"
#include "nsXPCOM.h"
@@ -148,17 +149,17 @@ LazyLogModule nsPluginLogging::gPluginLo
// #defines for plugin cache and prefs
#define NS_PREF_MAX_NUM_CACHED_INSTANCES "browser.plugins.max_num_cached_plugins"
// Raise this from '10' to '50' to work around a bug in Apple's current Java
// plugins on OS X Lion and SnowLeopard. See bug 705931.
#define DEFAULT_NUMBER_OF_STOPPED_INSTANCES 50
nsIFile *nsPluginHost::sPluginTempDir;
-nsPluginHost *nsPluginHost::sInst;
+StaticRefPtr<nsPluginHost> nsPluginHost::sInst;
/* to cope with short read */
/* we should probably put this into a global library now that this is the second
time we need this. */
static
int32_t
busy_beaver_PR_Read(PRFileDesc *fd, void * start, int32_t len)
{
@@ -294,38 +295,34 @@ nsPluginHost::nsPluginHost()
}
}
nsPluginHost::~nsPluginHost()
{
PLUGIN_LOG(PLUGIN_LOG_ALWAYS,("nsPluginHost::dtor\n"));
UnloadPlugins();
- sInst = nullptr;
}
NS_IMPL_ISUPPORTS(nsPluginHost,
nsIPluginHost,
nsIObserver,
nsITimerCallback,
nsISupportsWeakReference,
nsINamed)
already_AddRefed<nsPluginHost>
nsPluginHost::GetInst()
{
if (!sInst) {
sInst = new nsPluginHost();
- if (!sInst)
- return nullptr;
- NS_ADDREF(sInst);
+ ClearOnShutdown(&sInst);
}
- RefPtr<nsPluginHost> inst = sInst;
- return inst.forget();
+ return do_AddRef(sInst);
}
bool nsPluginHost::IsRunningPlugin(nsPluginTag * aPluginTag)
{
if (!aPluginTag || !aPluginTag->mPlugin) {
return false;
}
@@ -3402,17 +3399,16 @@ void nsPluginHost::CreateWidget(nsPlugin
}
NS_IMETHODIMP nsPluginHost::Observe(nsISupports *aSubject,
const char *aTopic,
const char16_t *someData)
{
if (!strcmp(NS_XPCOM_SHUTDOWN_OBSERVER_ID, aTopic)) {
UnloadPlugins();
- sInst->Release();
}
if (!strcmp(NS_PREFBRANCH_PREFCHANGE_TOPIC_ID, aTopic)) {
mPluginsDisabled = Preferences::GetBool("plugin.disable", false);
// Unload or load plugins as needed
if (mPluginsDisabled) {
UnloadPlugins();
} else {
LoadPlugins();
--- a/dom/plugins/base/nsPluginHost.h
+++ b/dom/plugins/base/nsPluginHost.h
@@ -2,16 +2,17 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsPluginHost_h_
#define nsPluginHost_h_
#include "mozilla/LinkedList.h"
+#include "mozilla/StaticPtr.h"
#include "nsIPluginHost.h"
#include "nsIObserver.h"
#include "nsCOMPtr.h"
#include "prlink.h"
#include "nsIPluginTag.h"
#include "nsPluginsDir.h"
#include "nsPluginDirServiceProvider.h"
@@ -410,17 +411,17 @@ private:
// In the content process, this stores the last epoch value observed
// when reading plugins from chrome.
uint32_t mPluginEpoch;
static nsIFile *sPluginTempDir;
// We need to hold a global ptr to ourselves because we register for
// two different CIDs for some reason...
- static nsPluginHost* sInst;
+ static mozilla::StaticRefPtr<nsPluginHost> sInst;
};
class PluginDestructionGuard : public mozilla::LinkedListElement<PluginDestructionGuard>
{
public:
explicit PluginDestructionGuard(nsNPAPIPluginInstance *aInstance);
explicit PluginDestructionGuard(NPP npp);
--- a/dom/workers/WorkerDebuggerManager.cpp
+++ b/dom/workers/WorkerDebuggerManager.cpp
@@ -4,16 +4,17 @@
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WorkerDebuggerManager.h"
#include "nsISimpleEnumerator.h"
#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
#include "WorkerPrivate.h"
USING_WORKERS_NAMESPACE
namespace {
class RegisterDebuggerMainThreadRunnable final : public mozilla::Runnable
@@ -64,18 +65,17 @@ private:
WorkerDebuggerManager* manager = WorkerDebuggerManager::Get();
MOZ_ASSERT(manager);
manager->UnregisterDebuggerMainThread(mWorkerPrivate);
return NS_OK;
}
};
-// Does not hold an owning reference.
-static WorkerDebuggerManager* gWorkerDebuggerManager;
+static StaticRefPtr<WorkerDebuggerManager> gWorkerDebuggerManager;
} /* anonymous namespace */
BEGIN_WORKERS_NAMESPACE
class WorkerDebuggerEnumerator final : public nsISimpleEnumerator
{
nsTArray<RefPtr<WorkerDebugger>> mDebuggers;
@@ -138,20 +138,21 @@ WorkerDebuggerManager::GetInstance()
WorkerDebuggerManager*
WorkerDebuggerManager::GetOrCreate()
{
AssertIsOnMainThread();
if (!gWorkerDebuggerManager) {
// The observer service now owns us until shutdown.
gWorkerDebuggerManager = new WorkerDebuggerManager();
- if (NS_FAILED(gWorkerDebuggerManager->Init())) {
+ if (NS_SUCCEEDED(gWorkerDebuggerManager->Init())) {
+ ClearOnShutdown(&gWorkerDebuggerManager);
+ } else {
NS_WARNING("Failed to initialize worker debugger manager!");
gWorkerDebuggerManager = nullptr;
- return nullptr;
}
}
return gWorkerDebuggerManager;
}
WorkerDebuggerManager*
WorkerDebuggerManager::Get()
--- a/extensions/cookie/nsPermissionManager.cpp
+++ b/extensions/cookie/nsPermissionManager.cpp
@@ -917,17 +917,20 @@ nsPermissionManager::~nsPermissionManage
for (auto iter = mPermissionKeyPromiseMap.Iter(); !iter.Done(); iter.Next()) {
if (iter.Data()) {
iter.Data()->Reject(NS_ERROR_FAILURE, __func__);
}
}
mPermissionKeyPromiseMap.Clear();
RemoveAllFromMemory();
- gPermissionManager = nullptr;
+ if (gPermissionManager) {
+ MOZ_ASSERT(gPermissionManager == this);
+ gPermissionManager = nullptr;
+ }
}
// static
already_AddRefed<nsIPermissionManager>
nsPermissionManager::GetXPCOMSingleton()
{
if (gPermissionManager) {
return do_AddRef(gPermissionManager);
@@ -936,21 +939,22 @@ nsPermissionManager::GetXPCOMSingleton()
// 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.
auto permManager = MakeRefPtr<nsPermissionManager>();
if (NS_SUCCEEDED(permManager->Init())) {
+ // Note: This is cleared in the nsPermissionManager destructor.
gPermissionManager = permManager.get();
return permManager.forget();
}
- return nullptr;;
+ 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/js/xpconnect/src/nsXPConnect.cpp
+++ b/js/xpconnect/src/nsXPConnect.cpp
@@ -105,16 +105,17 @@ nsXPConnect::~nsXPConnect()
NS_RELEASE(gSystemPrincipal);
gScriptSecurityManager = nullptr;
// shutdown the logging system
XPC_LOG_FINISH();
delete gPrimaryContext;
+ MOZ_ASSERT(gSelf == this);
gSelf = nullptr;
gOnceAliveNowDead = true;
}
// static
void
nsXPConnect::InitStatics()
{
--- a/layout/build/nsLayoutStatics.cpp
+++ b/layout/build/nsLayoutStatics.cpp
@@ -83,20 +83,16 @@
#include "nsXULPrototypeCache.h"
#include "nsXULTooltipListener.h"
#include "inDOMView.h"
#include "nsMenuBarListener.h"
#endif
-#ifdef MOZ_WEBSPEECH
-#include "nsSynthVoiceRegistry.h"
-#endif
-
#include "CubebUtils.h"
#include "Latency.h"
#include "WebAudioUtils.h"
#include "nsError.h"
#include "nsJSEnvironment.h"
#include "nsContentSink.h"
@@ -387,20 +383,16 @@ nsLayoutStatics::Shutdown()
nsXBLService::Shutdown();
nsAutoCopyListener::Shutdown();
FrameLayerBuilder::Shutdown();
CubebUtils::ShutdownLibrary();
AsyncLatencyLogger::ShutdownLogger();
WebAudioUtils::Shutdown();
-#ifdef MOZ_WEBSPEECH
- nsSynthVoiceRegistry::Shutdown();
-#endif
-
nsCORSListenerProxy::Shutdown();
PointerEventHandler::ReleaseStatics();
TouchManager::ReleaseStatics();
nsTreeSanitizer::ReleaseStatics();
--- a/modules/libjar/nsJARChannel.cpp
+++ b/modules/libjar/nsJARChannel.cpp
@@ -199,27 +199,23 @@ nsJARChannel::nsJARChannel()
, mStatus(NS_OK)
, mIsPending(false)
, mIsUnsafe(true)
, mBlockRemoteFiles(false)
{
mBlockRemoteFiles = Preferences::GetBool("network.jar.block-remote-files", false);
// hold an owning reference to the jar handler
- NS_ADDREF(gJarHandler);
+ mJarHandler = gJarHandler;
}
nsJARChannel::~nsJARChannel()
{
NS_ReleaseOnMainThreadSystemGroup("nsJARChannel::mLoadInfo",
mLoadInfo.forget());
-
- // release owning reference to the jar handler
- nsJARProtocolHandler *handler = gJarHandler;
- NS_RELEASE(handler); // nullptr parameter
}
NS_IMPL_ISUPPORTS_INHERITED(nsJARChannel,
nsHashPropertyBag,
nsIRequest,
nsIChannel,
nsIStreamListener,
nsIRequestObserver,
--- a/modules/libjar/nsJARChannel.h
+++ b/modules/libjar/nsJARChannel.h
@@ -21,16 +21,17 @@
#include "nsHashPropertyBag.h"
#include "nsIFile.h"
#include "nsIURI.h"
#include "nsCOMPtr.h"
#include "nsString.h"
#include "mozilla/Logging.h"
class nsJARInputThunk;
+class nsJARProtocolHandler;
class nsInputStreamPump;
//-----------------------------------------------------------------------------
class nsJARChannel final : public nsIJARChannel
, public mozilla::net::MemoryDownloader::IObserver
, public nsIStreamListener
, public nsIThreadRetargetableRequest
@@ -67,16 +68,17 @@ private:
nsresult aStatus,
mozilla::net::MemoryDownloader::Data aData)
override;
nsCString mSpec;
bool mOpened;
+ RefPtr<nsJARProtocolHandler> mJarHandler;
nsCOMPtr<nsIJARURI> mJarURI;
nsCOMPtr<nsIURI> mOriginalURI;
nsCOMPtr<nsISupports> mOwner;
nsCOMPtr<nsILoadInfo> mLoadInfo;
nsCOMPtr<nsIInterfaceRequestor> mCallbacks;
nsCOMPtr<nsISupports> mSecurityInfo;
nsCOMPtr<nsIProgressEventSink> mProgressSink;
nsCOMPtr<nsILoadGroup> mLoadGroup;
--- a/modules/libjar/nsJARFactory.cpp
+++ b/modules/libjar/nsJARFactory.cpp
@@ -37,28 +37,19 @@ static const mozilla::Module::CIDEntry k
static const mozilla::Module::ContractIDEntry kJARContracts[] = {
{ "@mozilla.org/libjar/zip-reader;1", &kNS_ZIPREADER_CID },
{ "@mozilla.org/libjar/zip-reader-cache;1", &kNS_ZIPREADERCACHE_CID },
{ NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "jar", &kNS_JARPROTOCOLHANDLER_CID },
{ nullptr }
};
-// Jar module shutdown hook
-static void nsJarShutdown()
-{
- // Make sure to not null out gJarHandler here, because we may have
- // still-live nsJARChannels that will want to release it.
- nsJARProtocolHandler *handler = gJarHandler;
- NS_IF_RELEASE(handler);
-}
-
static const mozilla::Module kJARModule = {
mozilla::Module::kVersion,
kJARCIDs,
kJARContracts,
nullptr,
nullptr,
nullptr,
- nsJarShutdown
+ nullptr
};
NSMODULE_DEFN(nsJarModule) = &kJARModule;
--- a/modules/libjar/nsJARProtocolHandler.cpp
+++ b/modules/libjar/nsJARProtocolHandler.cpp
@@ -1,13 +1,14 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+#include "mozilla/ClearOnShutdown.h"
#include "nsAutoPtr.h"
#include "nsJARProtocolHandler.h"
#include "nsIIOService.h"
#include "nsCRT.h"
#include "nsIComponentManager.h"
#include "nsIServiceManager.h"
#include "nsJARURI.h"
#include "nsIURL.h"
@@ -19,28 +20,25 @@
#include "nsThreadUtils.h"
static NS_DEFINE_CID(kZipReaderCacheCID, NS_ZIPREADERCACHE_CID);
#define NS_JAR_CACHE_SIZE 32
//-----------------------------------------------------------------------------
-nsJARProtocolHandler *gJarHandler = nullptr;
+StaticRefPtr<nsJARProtocolHandler> gJarHandler;
nsJARProtocolHandler::nsJARProtocolHandler()
{
MOZ_ASSERT(NS_IsMainThread());
}
nsJARProtocolHandler::~nsJARProtocolHandler()
-{
- MOZ_ASSERT(gJarHandler == this);
- gJarHandler = nullptr;
-}
+{}
nsresult
nsJARProtocolHandler::Init()
{
nsresult rv;
mJARCache = do_CreateInstance(kZipReaderCacheCID, &rv);
if (NS_FAILED(rv)) return rv;
@@ -62,25 +60,22 @@ NS_IMPL_ISUPPORTS(nsJARProtocolHandler,
nsIJARProtocolHandler,
nsIProtocolHandler,
nsISupportsWeakReference)
already_AddRefed<nsJARProtocolHandler>
nsJARProtocolHandler::GetSingleton()
{
if (!gJarHandler) {
- auto jar = MakeRefPtr<nsJARProtocolHandler>();
- gJarHandler = jar.get();
- if (NS_FAILED(jar->Init())) {
+ gJarHandler = new nsJARProtocolHandler();
+ if (NS_SUCCEEDED(gJarHandler->Init())) {
+ ClearOnShutdown(&gJarHandler);
+ } else {
gJarHandler = nullptr;
- return nullptr;
}
- // We release this reference on module shutdown.
- NS_ADDREF(gJarHandler);
- return jar.forget();
}
return do_AddRef(gJarHandler);
}
NS_IMETHODIMP
nsJARProtocolHandler::GetJARCache(nsIZipReaderCache* *result)
{
*result = mJARCache;
--- a/modules/libjar/nsJARProtocolHandler.h
+++ b/modules/libjar/nsJARProtocolHandler.h
@@ -1,16 +1,17 @@
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
#ifndef nsJARProtocolHandler_h__
#define nsJARProtocolHandler_h__
+#include "mozilla/StaticPtr.h"
#include "nsIJARProtocolHandler.h"
#include "nsIProtocolHandler.h"
#include "nsIJARURI.h"
#include "nsIZipReader.h"
#include "nsIMIMEService.h"
#include "nsWeakReference.h"
#include "nsCOMPtr.h"
@@ -34,17 +35,17 @@ public:
nsIZipReaderCache *JarCache() { return mJARCache; }
protected:
virtual ~nsJARProtocolHandler();
nsCOMPtr<nsIZipReaderCache> mJARCache;
nsCOMPtr<nsIMIMEService> mMimeService;
};
-extern nsJARProtocolHandler *gJarHandler;
+extern mozilla::StaticRefPtr<nsJARProtocolHandler> gJarHandler;
#define NS_JARPROTOCOLHANDLER_CID \
{ /* 0xc7e410d4-0x85f2-11d3-9f63-006008a6efe9 */ \
0xc7e410d4, \
0x85f2, \
0x11d3, \
{0x9f, 0x63, 0x00, 0x60, 0x08, 0xa6, 0xef, 0xe9} \
}
--- a/netwerk/base/nsIOService.cpp
+++ b/netwerk/base/nsIOService.cpp
@@ -73,17 +73,17 @@ namespace net {
// but the old names are still used to preserve backward compatibility.
#define NECKO_BUFFER_CACHE_COUNT_PREF "network.buffer.cache.count"
#define NECKO_BUFFER_CACHE_SIZE_PREF "network.buffer.cache.size"
#define NETWORK_NOTIFY_CHANGED_PREF "network.notify.changed"
#define NETWORK_CAPTIVE_PORTAL_PREF "network.captive-portal-service.enabled"
#define MAX_RECURSION_COUNT 50
-nsIOService* gIOService = nullptr;
+nsIOService* gIOService;
static bool gHasWarnedUploadChannel2;
static bool gCaptivePortalEnabled = false;
static LazyLogModule gIOServiceLog("nsIOService");
#undef LOG
#define LOG(args) MOZ_LOG(gIOServiceLog, LogLevel::Debug, args)
// A general port blacklist. Connections to these ports will not be allowed
// unless the protocol overrides.
@@ -264,17 +264,20 @@ nsIOService::Init()
SetOffline(false);
return NS_OK;
}
nsIOService::~nsIOService()
{
- gIOService = nullptr;
+ if (gIOService) {
+ MOZ_ASSERT(gIOService == this);
+ gIOService = nullptr;
+ }
}
nsresult
nsIOService::InitializeCaptivePortalService()
{
if (XRE_GetProcessType() != GeckoProcessType_Default) {
// We only initalize a captive portal service in the main process
return NS_OK;
@@ -350,23 +353,20 @@ nsIOService::InitializeProtocolProxyServ
return rv;
}
already_AddRefed<nsIOService>
nsIOService::GetInstance() {
if (!gIOService) {
RefPtr<nsIOService> ios = new nsIOService();
- gIOService = ios.get();
- if (NS_FAILED(ios->Init())) {
- gIOService = nullptr;
- return nullptr;
+ if (NS_SUCCEEDED(ios->Init())) {
+ MOZ_ASSERT(gIOService == ios.get());
+ return ios.forget();
}
-
- return ios.forget();
}
return do_AddRef(gIOService);
}
NS_IMPL_ISUPPORTS(nsIOService,
nsIIOService,
nsIIOService2,
nsINetUtil,
--- a/netwerk/dns/ChildDNSService.cpp
+++ b/netwerk/dns/ChildDNSService.cpp
@@ -6,37 +6,40 @@
#include "nsIDNSListener.h"
#include "nsIIOService.h"
#include "nsIThread.h"
#include "nsThreadUtils.h"
#include "nsIXPConnect.h"
#include "nsIPrefService.h"
#include "nsIProtocolProxyService.h"
#include "nsNetCID.h"
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
#include "mozilla/SystemGroup.h"
#include "mozilla/net/NeckoChild.h"
#include "mozilla/net/DNSListenerProxy.h"
#include "nsServiceManagerUtils.h"
namespace mozilla {
namespace net {
//-----------------------------------------------------------------------------
// ChildDNSService
//-----------------------------------------------------------------------------
-static ChildDNSService *gChildDNSService;
+static StaticRefPtr<ChildDNSService> gChildDNSService;
static const char kPrefNameDisablePrefetch[] = "network.dns.disablePrefetch";
already_AddRefed<ChildDNSService> ChildDNSService::GetSingleton()
{
MOZ_ASSERT(IsNeckoChild());
if (!gChildDNSService) {
gChildDNSService = new ChildDNSService();
+ ClearOnShutdown(&gChildDNSService);
}
return do_AddRef(gChildDNSService);
}
NS_IMPL_ISUPPORTS(ChildDNSService,
nsIDNSService,
nsPIDNSService,
--- a/netwerk/dns/nsDNSService2.cpp
+++ b/netwerk/dns/nsDNSService2.cpp
@@ -29,20 +29,22 @@
#include "nsIOService.h"
#include "nsCharSeparatedTokenizer.h"
#include "nsNetAddr.h"
#include "nsProxyRelease.h"
#include "nsIObserverService.h"
#include "nsINetworkLinkService.h"
#include "mozilla/Attributes.h"
+#include "mozilla/ClearOnShutdown.h"
#include "mozilla/net/NeckoCommon.h"
#include "mozilla/net/ChildDNSService.h"
#include "mozilla/net/DNSListenerProxy.h"
#include "mozilla/Services.h"
+#include "mozilla/StaticPtr.h"
using namespace mozilla;
using namespace mozilla::net;
static const char kPrefDnsCacheEntries[] = "network.dnsCacheEntries";
static const char kPrefDnsCacheExpiration[] = "network.dnsCacheExpiration";
static const char kPrefDnsCacheGrace[] = "network.dnsCacheExpirationGracePeriod";
static const char kPrefIPv4OnlyDomains[] = "network.dns.ipv4OnlyDomains";
@@ -492,45 +494,43 @@ nsDNSService::~nsDNSService() = default;
NS_IMPL_ISUPPORTS(nsDNSService, nsIDNSService, nsPIDNSService, nsIObserver,
nsIMemoryReporter)
/******************************************************************************
* nsDNSService impl:
* singleton instance ctor/dtor methods
******************************************************************************/
-static nsDNSService *gDNSService;
+static StaticRefPtr<nsDNSService> gDNSService;
already_AddRefed<nsIDNSService>
nsDNSService::GetXPCOMSingleton()
{
if (IsNeckoChild()) {
return ChildDNSService::GetSingleton();
}
return GetSingleton();
}
already_AddRefed<nsDNSService>
nsDNSService::GetSingleton()
{
NS_ASSERTION(!IsNeckoChild(), "not a parent process");
- if (gDNSService) {
- return do_AddRef(gDNSService);
+ if (!gDNSService) {
+ gDNSService = new nsDNSService();
+ if (NS_SUCCEEDED(gDNSService->Init())) {
+ ClearOnShutdown(&gDNSService);
+ } else {
+ gDNSService = nullptr;
+ }
}
- auto dns = MakeRefPtr<nsDNSService>();
- gDNSService = dns.get();
- if (NS_FAILED(dns->Init())) {
- gDNSService = nullptr;
- return nullptr;
- }
-
- return dns.forget();
+ return do_AddRef(gDNSService);
}
NS_IMETHODIMP
nsDNSService::Init()
{
if (mResolver)
return NS_OK;
NS_ENSURE_TRUE(!mResolver, NS_ERROR_ALREADY_INITIALIZED);
--- a/storage/VacuumManager.cpp
+++ b/storage/VacuumManager.cpp
@@ -315,17 +315,19 @@ already_AddRefed<VacuumManager>
VacuumManager::getSingleton()
{
//Don't allocate it in the child Process.
if (!XRE_IsParentProcess()) {
return nullptr;
}
if (!gVacuumManager) {
- gVacuumManager = new VacuumManager();
+ auto manager = MakeRefPtr<VacuumManager>();
+ MOZ_ASSERT(gVacuumManager == manager.get());
+ return manager.forget();
}
return do_AddRef(gVacuumManager);
}
VacuumManager::VacuumManager()
: mParticipants("vacuum-participant")
{
MOZ_ASSERT(!gVacuumManager,
--- a/storage/mozStorageService.cpp
+++ b/storage/mozStorageService.cpp
@@ -217,23 +217,23 @@ Service::getSingleton()
}
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);
RefPtr<Service> service = new Service();
- gService = service.get();
- if (NS_FAILED(service->initialize())) {
- gService = nullptr;
- return nullptr;
+ if (NS_SUCCEEDED(service->initialize())) {
+ // Note: This is cleared in the Service destructor.
+ gService = service.get();
+ return service.forget();
}
- return service.forget();
+ return nullptr;
}
nsIXPConnect *Service::sXPConnect = nullptr;
// static
already_AddRefed<nsIXPConnect>
Service::getXPConnect()
{
--- a/toolkit/components/downloads/ApplicationReputation.cpp
+++ b/toolkit/components/downloads/ApplicationReputation.cpp
@@ -1551,16 +1551,17 @@ NS_IMPL_ISUPPORTS(ApplicationReputationS
ApplicationReputationService*
ApplicationReputationService::gApplicationReputationService = nullptr;
already_AddRefed<ApplicationReputationService>
ApplicationReputationService::GetSingleton()
{
if (!gApplicationReputationService) {
+ // Note: This is cleared in the new ApplicationReputationService destructor.
gApplicationReputationService = new ApplicationReputationService();
}
return do_AddRef(gApplicationReputationService);
}
ApplicationReputationService::ApplicationReputationService()
{
LOG(("Application reputation service started up"));
--- a/toolkit/components/downloads/nsDownloadManager.cpp
+++ b/toolkit/components/downloads/nsDownloadManager.cpp
@@ -28,26 +28,27 @@ nsDownloadManager *nsDownloadManager::gD
already_AddRefed<nsDownloadManager>
nsDownloadManager::GetSingleton()
{
if (gDownloadManagerService) {
return do_AddRef(gDownloadManagerService);
}
auto serv = MakeRefPtr<nsDownloadManager>();
+ // Note: This is cleared in the nsDownloadManager constructor.
gDownloadManagerService = serv.get();
- if (NS_FAILED(serv->Init())) {
- gDownloadManagerService = nullptr;
- return nullptr;
+ if (NS_SUCCEEDED(serv->Init())) {
+ return serv.forget();
}
- return serv.forget();
+ return nullptr;
}
nsDownloadManager::~nsDownloadManager()
{
+ MOZ_ASSERT(gDownloadManagerService == this);
gDownloadManagerService = nullptr;
}
nsresult
nsDownloadManager::Init()
{
nsresult rv;
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -1936,16 +1936,17 @@ History::History()
(void)os->AddObserver(this, TOPIC_PLACES_SHUTDOWN, false);
}
}
History::~History()
{
UnregisterWeakMemoryReporter(this);
+ MOZ_ASSERT(gService == this);
gService = nullptr;
}
void
History::InitMemoryReporter()
{
RegisterWeakMemoryReporter(this);
}
@@ -2420,19 +2421,20 @@ History::GetService()
return gService;
}
/* static */
already_AddRefed<History>
History::GetSingleton()
{
if (!gService) {
- gService = new History();
- NS_ENSURE_TRUE(gService, nullptr);
- gService->InitMemoryReporter();
+ RefPtr<History> svc = new History();
+ MOZ_ASSERT(gService == svc.get());
+ svc->InitMemoryReporter();
+ return svc.forget();
}
return do_AddRef(gService);
}
mozIStorageConnection*
History::GetDBConn()
{
--- a/toolkit/mozapps/extensions/AddonPathService.cpp
+++ b/toolkit/mozapps/extensions/AddonPathService.cpp
@@ -45,16 +45,17 @@ struct PathEntryComparator
};
AddonPathService::AddonPathService()
{
}
AddonPathService::~AddonPathService()
{
+ MOZ_ASSERT(sInstance == this);
sInstance = nullptr;
}
NS_IMPL_ISUPPORTS(AddonPathService, amIAddonPathService)
AddonPathService *AddonPathService::sInstance;
/* static */ already_AddRefed<AddonPathService>
--- a/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
+++ b/uriloader/prefetch/nsOfflineCacheUpdateService.cpp
@@ -251,16 +251,17 @@ nsOfflineCacheUpdateService::nsOfflineCa
MOZ_ASSERT(NS_IsMainThread());
Preferences::AddBoolVarCache(&sAllowOfflineCache,
"browser.cache.offline.enable",
true);
}
nsOfflineCacheUpdateService::~nsOfflineCacheUpdateService()
{
+ MOZ_ASSERT(gOfflineCacheUpdateService == this);
gOfflineCacheUpdateService = nullptr;
}
nsresult
nsOfflineCacheUpdateService::Init()
{
// Observe xpcom-shutdown event
nsCOMPtr<nsIObserverService> observerService =
@@ -292,21 +293,19 @@ nsOfflineCacheUpdateService::Init()
}
/* static */
already_AddRefed<nsOfflineCacheUpdateService>
nsOfflineCacheUpdateService::GetInstance()
{
if (!gOfflineCacheUpdateService) {
auto serv = MakeRefPtr<nsOfflineCacheUpdateService>();
- gOfflineCacheUpdateService = serv.get();
- if (NS_FAILED(serv->Init())) {
- gOfflineCacheUpdateService = nullptr;
- return nullptr;
- }
+ if (NS_FAILED(serv->Init()))
+ serv = nullptr;
+ MOZ_ASSERT(gOfflineCacheUpdateService == serv.get());
return serv.forget();
}
return do_AddRef(gOfflineCacheUpdateService);
}
/* static */
nsOfflineCacheUpdateService *