Bug 1330747 Always nullptr check return value from ServiceWorkerManager::GetInstance(). r=asuth a=lizzard
authorBen Kelly <ben@wanderview.com>
Fri, 13 Jan 2017 17:14:54 -0800
changeset 366385 be9be2c13b4dc9038b331a91f923a4658014bae4
parent 366384 06ae7f59eff7c9ec09d176d8e3b02929b9157ec7
child 366386 964820fe861b735957eb7e35dfa39790ab31f5e5
push id6795
push userjlund@mozilla.com
push dateMon, 23 Jan 2017 14:19:46 +0000
treeherdermozilla-beta@76101b503191 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth, lizzard
bugs1330747
milestone52.0a2
Bug 1330747 Always nullptr check return value from ServiceWorkerManager::GetInstance(). r=asuth a=lizzard
dom/ipc/ContentChild.cpp
dom/notification/Notification.cpp
dom/workers/ServiceWorkerClients.cpp
dom/workers/ServiceWorkerEvents.cpp
dom/workers/ServiceWorkerJob.cpp
dom/workers/ServiceWorkerManager.cpp
dom/workers/ServiceWorkerManagerChild.cpp
dom/workers/ServiceWorkerPrivate.cpp
dom/workers/ServiceWorkerRegisterJob.cpp
dom/workers/ServiceWorkerRegistration.cpp
dom/workers/ServiceWorkerRegistrationInfo.cpp
dom/workers/ServiceWorkerUnregisterJob.cpp
dom/workers/ServiceWorkerUpdateJob.cpp
dom/workers/ServiceWorkerUpdateJob.h
dom/workers/WorkerPrivate.cpp
dom/workers/WorkerScope.cpp
--- a/dom/ipc/ContentChild.cpp
+++ b/dom/ipc/ContentChild.cpp
@@ -2466,17 +2466,20 @@ ContentChild::RecvAppInit()
 
   return true;
 }
 
 bool
 ContentChild::RecvInitServiceWorkers(const ServiceWorkerConfiguration& aConfig)
 {
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    // browser shutdown began
+    return true;
+  }
   swm->LoadRegistrations(aConfig.serviceWorkerRegistrations());
   return true;
 }
 
 bool
 ContentChild::RecvInitBlobURLs(nsTArray<BlobURLRegistrationData>&& aRegistrations)
 {
   for (uint32_t i = 0; i < aRegistrations.Length(); ++i) {
--- a/dom/notification/Notification.cpp
+++ b/dom/notification/Notification.cpp
@@ -2553,16 +2553,22 @@ public:
     nsIPrincipal* principal = mWorkerPrivate->GetPrincipal();
     mRv = CheckScope(principal, mScope);
 
     if (NS_FAILED(mRv)) {
       return true;
     }
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      // browser shutdown began
+      mRv = NS_ERROR_FAILURE;
+      return true;
+    }
+
     RefPtr<ServiceWorkerRegistrationInfo> registration =
       swm->GetRegistration(principal, mScope);
 
     // This is coming from a ServiceWorkerRegistration.
     MOZ_ASSERT(registration);
 
     if (!registration->GetActive() ||
         registration->GetActive()->ID() != mWorkerPrivate->ServiceWorkerID()) {
--- a/dom/workers/ServiceWorkerClients.cpp
+++ b/dom/workers/ServiceWorkerClients.cpp
@@ -126,20 +126,26 @@ public:
     MutexAutoLock lock(mPromiseProxy->Lock());
     if (mPromiseProxy->CleanedUp()) {
       return NS_OK;
     }
 
     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
 
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    UniquePtr<ServiceWorkerClientInfo> result;
     ErrorResult rv;
-    UniquePtr<ServiceWorkerClientInfo> result = swm->GetClient(workerPrivate->GetPrincipal(),
-                                                               mClientId, rv);
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      rv = NS_ERROR_FAILURE;
+    } else {
+      result = swm->GetClient(workerPrivate->GetPrincipal(), mClientId, rv);
+    }
+
     RefPtr<ResolvePromiseWorkerRunnable> r =
       new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
                                        mPromiseProxy, Move(result),
                                        rv.StealNSResult());
     rv.SuppressException();
 
     r->Dispatch();
     return NS_OK;
@@ -205,21 +211,22 @@ public:
   {
     AssertIsOnMainThread();
 
     MutexAutoLock lock(mPromiseProxy->Lock());
     if (mPromiseProxy->CleanedUp()) {
       return NS_OK;
     }
 
+    nsTArray<ServiceWorkerClientInfo> result;
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    nsTArray<ServiceWorkerClientInfo> result;
-
-    swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(), mScope,
-                       mIncludeUncontrolled, result);
+    if (swm) {
+      swm->GetAllClients(mPromiseProxy->GetWorkerPrivate()->GetPrincipal(),
+                         mScope, mIncludeUncontrolled, result);
+    }
     RefPtr<ResolvePromiseWorkerRunnable> r =
       new ResolvePromiseWorkerRunnable(mPromiseProxy->GetWorkerPrivate(),
                                        mPromiseProxy, result);
 
     r->Dispatch();
     return NS_OK;
   }
 };
@@ -283,21 +290,25 @@ public:
     MutexAutoLock lock(mPromiseProxy->Lock());
     if (mPromiseProxy->CleanedUp()) {
       return NS_OK;
     }
 
     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
     MOZ_ASSERT(workerPrivate);
 
+    nsresult rv = NS_OK;
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    nsresult rv = swm->ClaimClients(workerPrivate->GetPrincipal(),
-                                    mScope, mServiceWorkerID);
+    if (!swm) {
+      // browser shutdown
+      rv = NS_ERROR_FAILURE;
+    } else {
+      rv = swm->ClaimClients(workerPrivate->GetPrincipal(), mScope,
+                             mServiceWorkerID);
+    }
 
     RefPtr<ResolveClaimRunnable> r =
       new ResolveClaimRunnable(workerPrivate, mPromiseProxy, rv);
 
     r->Dispatch();
     return NS_OK;
   }
 };
@@ -531,17 +542,20 @@ public:
       nsCOMPtr<nsIDocShell> docShell = window->GetDocShell();
       nsCOMPtr<nsIWebProgress> webProgress = do_GetInterface(docShell);
 
       if (!webProgress) {
         return NS_ERROR_FAILURE;
       }
 
       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-      MOZ_ASSERT(swm);
+      if (!swm) {
+        // browser shutdown
+        return NS_ERROR_FAILURE;
+      }
 
       nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
       MOZ_ASSERT(principal);
       RefPtr<ServiceWorkerRegistrationInfo> registration =
         swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
       if (NS_WARN_IF(!registration)) {
         return NS_ERROR_FAILURE;
       }
@@ -567,17 +581,20 @@ public:
       // to try opening a window again.
       nsCOMPtr<nsIObserverService> os = services::GetObserverService();
       NS_ENSURE_STATE(os);
 
       WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
       MOZ_ASSERT(workerPrivate);
 
       RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-      MOZ_ASSERT(swm);
+      if (!swm) {
+        // browser shutdown
+        return NS_ERROR_FAILURE;
+      }
 
       nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
       MOZ_ASSERT(principal);
 
       RefPtr<ServiceWorkerRegistrationInfo> registration =
         swm->GetRegistration(principal, NS_ConvertUTF16toUTF8(mScope));
       if (NS_WARN_IF(!registration)) {
         return NS_ERROR_FAILURE;
--- a/dom/workers/ServiceWorkerEvents.cpp
+++ b/dom/workers/ServiceWorkerEvents.cpp
@@ -867,16 +867,20 @@ public:
         NewRunnableMethod(this, &WaitUntilHandler::ReportOnMainThread)));
   }
 
   void
   ReportOnMainThread()
   {
     AssertIsOnMainThread();
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      // browser shutdown
+      return;
+    }
 
     // TODO: Make the error message a localized string. (bug 1222720)
     nsString message;
     message.AppendLiteral("Service worker event waitUntil() was passed a "
                           "promise that rejected with '");
     message.Append(mRejectValue);
     message.AppendLiteral("'.");
 
--- a/dom/workers/ServiceWorkerJob.cpp
+++ b/dom/workers/ServiceWorkerJob.cpp
@@ -96,17 +96,22 @@ ServiceWorkerJob::Start(Callback* aFinal
 
   nsCOMPtr<nsIRunnable> runnable =
     NewRunnableMethod(this, &ServiceWorkerJob::AsyncExecute);
 
   // We may have to wait for the PBackground actor to be initialized
   // before proceeding.  We should always be able to get a ServiceWorkerManager,
   // however, since Start() should not be called during shutdown.
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm) {
+    // browser shutdown
+    return;
+  }
   if (!swm->HasBackgroundActor()) {
+    // waiting to initialize
     swm->AppendPendingOperation(runnable);
     return;
   }
 
   // Otherwise start asynchronously.  We should never run a job synchronously.
   MOZ_ALWAYS_TRUE(NS_SUCCEEDED(
     NS_DispatchToMainThread(runnable.forget())));
 }
--- a/dom/workers/ServiceWorkerManager.cpp
+++ b/dom/workers/ServiceWorkerManager.cpp
@@ -323,19 +323,20 @@ public:
     , mScope(aScope)
   {}
 
   NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    swm->PropagateSoftUpdate(mOriginAttributes, mScope);
+    if (swm) {
+      swm->PropagateSoftUpdate(mOriginAttributes, mScope);
+    }
+
     return NS_OK;
   }
 
 private:
   ~PropagateSoftUpdateRunnable()
   {}
 
   const PrincipalOriginAttributes mOriginAttributes;
@@ -355,21 +356,18 @@ public:
     MOZ_ASSERT(aPrincipal);
   }
 
   NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    nsresult rv = swm->PropagateUnregister(mPrincipal, mCallback, mScope);
-    if (NS_WARN_IF(NS_FAILED(rv))) {
-      return rv;
+    if (swm) {
+      swm->PropagateUnregister(mPrincipal, mCallback, mScope);
     }
 
     return NS_OK;
   }
 
 private:
   ~PropagateUnregisterRunnable()
   {}
@@ -385,19 +383,20 @@ public:
   explicit RemoveRunnable(const nsACString& aHost)
   {}
 
   NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    swm->Remove(mHost);
+    if (swm) {
+      swm->Remove(mHost);
+    }
+
     return NS_OK;
   }
 
 private:
   ~RemoveRunnable()
   {}
 
   const nsCString mHost;
@@ -409,19 +408,20 @@ public:
   explicit PropagateRemoveRunnable(const nsACString& aHost)
   {}
 
   NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    swm->PropagateRemove(mHost);
+    if (swm) {
+      swm->PropagateRemove(mHost);
+    }
+
     return NS_OK;
   }
 
 private:
   ~PropagateRemoveRunnable()
   {}
 
   const nsCString mHost;
@@ -433,19 +433,20 @@ public:
   PropagateRemoveAllRunnable()
   {}
 
   NS_IMETHOD Run() override
   {
     AssertIsOnMainThread();
 
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
-
-    swm->PropagateRemoveAll();
+    if (swm) {
+      swm->PropagateRemoveAll();
+    }
+
     return NS_OK;
   }
 
 private:
   ~PropagateRemoveAllRunnable()
   {}
 };
 
@@ -649,16 +650,20 @@ public:
   GetRegistrationsRunnable(nsPIDOMWindowInner* aWindow, Promise* aPromise)
     : mWindow(aWindow), mPromise(aPromise)
   {}
 
   NS_IMETHOD
   Run() override
   {
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
+      return NS_OK;
+    }
 
     nsIDocument* doc = mWindow->GetExtantDoc();
     if (!doc) {
       mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
       return NS_OK;
     }
 
     nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
@@ -773,16 +778,20 @@ public:
                           const nsAString& aDocumentURL)
     : mWindow(aWindow), mPromise(aPromise), mDocumentURL(aDocumentURL)
   {}
 
   NS_IMETHOD
   Run() override
   {
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
+      return NS_OK;
+    }
 
     nsIDocument* doc = mWindow->GetExtantDoc();
     if (!doc) {
       mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
       return NS_OK;
     }
 
     nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
@@ -873,16 +882,20 @@ public:
   GetReadyPromiseRunnable(nsPIDOMWindowInner* aWindow, Promise* aPromise)
     : mWindow(aWindow), mPromise(aPromise)
   {}
 
   NS_IMETHOD
   Run() override
   {
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (!swm) {
+      mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
+      return NS_OK;
+    }
 
     nsIDocument* doc = mWindow->GetExtantDoc();
     if (!doc) {
       mPromise->MaybeReject(NS_ERROR_UNEXPECTED);
       return NS_OK;
     }
 
     nsCOMPtr<nsIURI> docURI = doc->GetDocumentURI();
@@ -1883,17 +1896,20 @@ ServiceWorkerManager::PrincipalToScopeKe
 /* static */ void
 ServiceWorkerManager::AddScopeAndRegistration(const nsACString& aScope,
                                               ServiceWorkerRegistrationInfo* aInfo)
 {
   MOZ_ASSERT(aInfo);
   MOZ_ASSERT(aInfo->mPrincipal);
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    // browser shutdown
+    return;
+  }
 
   nsAutoCString scopeKey;
   nsresult rv = swm->PrincipalToScopeKey(aInfo->mPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   MOZ_ASSERT(!scopeKey.IsEmpty());
@@ -1934,19 +1950,18 @@ ServiceWorkerManager::AddScopeAndRegistr
 ServiceWorkerManager::FindScopeForPath(const nsACString& aScopeKey,
                                        const nsACString& aPath,
                                        RegistrationDataPerPrincipal** aData,
                                        nsACString& aMatch)
 {
   MOZ_ASSERT(aData);
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
-
-  if (!swm->mRegistrationInfos.Get(aScopeKey, aData)) {
+
+  if (!swm || !swm->mRegistrationInfos.Get(aScopeKey, aData)) {
     return false;
   }
 
   for (uint32_t i = 0; i < (*aData)->mOrderedScopes.Length(); ++i) {
     const nsCString& current = (*aData)->mOrderedScopes[i];
     if (StringBeginsWith(aPath, current)) {
       aMatch = current;
       return true;
@@ -1956,17 +1971,19 @@ ServiceWorkerManager::FindScopeForPath(c
   return false;
 }
 
 /* static */ bool
 ServiceWorkerManager::HasScope(nsIPrincipal* aPrincipal,
                                const nsACString& aScope)
 {
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    return false;
+  }
 
   nsAutoCString scopeKey;
   nsresult rv = PrincipalToScopeKey(aPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return false;
   }
 
   RegistrationDataPerPrincipal* data;
@@ -1976,17 +1993,19 @@ ServiceWorkerManager::HasScope(nsIPrinci
 
   return data->mOrderedScopes.Contains(aScope);
 }
 
 /* static */ void
 ServiceWorkerManager::RemoveScopeAndRegistration(ServiceWorkerRegistrationInfo* aRegistration)
 {
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    return;
+  }
 
   nsAutoCString scopeKey;
   nsresult rv = swm->PrincipalToScopeKey(aRegistration->mPrincipal, scopeKey);
   if (NS_WARN_IF(NS_FAILED(rv))) {
     return;
   }
 
   RegistrationDataPerPrincipal* data;
@@ -3245,27 +3264,26 @@ ServiceWorkerManager::Remove(const nsACS
   // We need to postpone this operation in case we don't have an actor because
   // this is needed by the ForceUnregister.
   if (!mActor) {
     RefPtr<nsIRunnable> runnable = new RemoveRunnable(aHost);
     AppendPendingOperation(runnable);
     return;
   }
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
     ServiceWorkerManager::RegistrationDataPerPrincipal* data = it1.UserData();
     for (auto it2 = data->mInfos.Iter(); !it2.Done(); it2.Next()) {
       ServiceWorkerRegistrationInfo* reg = it2.UserData();
       nsCOMPtr<nsIURI> scopeURI;
       nsresult rv = NS_NewURI(getter_AddRefs(scopeURI), it2.Key(),
                               nullptr, nullptr);
       // This way subdomains are also cleared.
       if (NS_SUCCEEDED(rv) && HasRootDomain(scopeURI, aHost)) {
-        swm->ForceUnregister(data, reg);
+        ForceUnregister(data, reg);
       }
     }
   }
 }
 
 void
 ServiceWorkerManager::PropagateRemove(const nsACString& aHost)
 {
@@ -3280,22 +3298,21 @@ ServiceWorkerManager::PropagateRemove(co
   mActor->SendPropagateRemove(nsCString(aHost));
 }
 
 void
 ServiceWorkerManager::RemoveAll()
 {
   AssertIsOnMainThread();
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   for (auto it1 = mRegistrationInfos.Iter(); !it1.Done(); it1.Next()) {
     ServiceWorkerManager::RegistrationDataPerPrincipal* data = it1.UserData();
     for (auto it2 = data->mInfos.Iter(); !it2.Done(); it2.Next()) {
       ServiceWorkerRegistrationInfo* reg = it2.UserData();
-      swm->ForceUnregister(data, reg);
+      ForceUnregister(data, reg);
     }
   }
 }
 
 void
 ServiceWorkerManager::PropagateRemoveAll()
 {
   AssertIsOnMainThread();
@@ -3330,18 +3347,17 @@ ServiceWorkerManager::RemoveAllRegistrat
       MOZ_ASSERT(reg->mPrincipal);
 
       bool matches =
         aPattern->Matches(BasePrincipal::Cast(reg->mPrincipal)->OriginAttributesRef());
       if (!matches) {
         continue;
       }
 
-      RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-      swm->ForceUnregister(data, reg);
+      ForceUnregister(data, reg);
     }
   }
 }
 
 NS_IMETHODIMP
 ServiceWorkerManager::AddListener(nsIServiceWorkerManagerListener* aListener)
 {
   AssertIsOnMainThread();
@@ -3676,17 +3692,19 @@ class ServiceWorkerManager::Interception
   // Weak reference to channel is safe, because the channel holds a
   // reference to this object.  Also, the pointer is only used for
   // comparison purposes.
   nsIInterceptedChannel* mChannel;
 
   ~InterceptionReleaseHandle()
   {
     RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    swm->RemoveNavigationInterception(mScope, mChannel);
+    if (swm) {
+      swm->RemoveNavigationInterception(mScope, mChannel);
+    }
   }
 
 public:
   InterceptionReleaseHandle(const nsACString& aScope,
                             nsIInterceptedChannel* aChannel)
     : mScope(aScope)
     , mChannel(aChannel)
   {
--- a/dom/workers/ServiceWorkerManagerChild.cpp
+++ b/dom/workers/ServiceWorkerManagerChild.cpp
@@ -19,48 +19,53 @@ bool
 ServiceWorkerManagerChild::RecvNotifyRegister(
                                      const ServiceWorkerRegistrationData& aData)
 {
   if (mShuttingDown) {
     return true;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (swm) {
+    swm->LoadRegistration(aData);
+  }
 
-  swm->LoadRegistration(aData);
   return true;
 }
 
 bool
 ServiceWorkerManagerChild::RecvNotifySoftUpdate(
                                       const PrincipalOriginAttributes& aOriginAttributes,
                                       const nsString& aScope)
 {
   if (mShuttingDown) {
     return true;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (swm) {
+    swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope));
+  }
 
-  swm->SoftUpdate(aOriginAttributes, NS_ConvertUTF16toUTF8(aScope));
   return true;
 }
 
 bool
 ServiceWorkerManagerChild::RecvNotifyUnregister(const PrincipalInfo& aPrincipalInfo,
                                                 const nsString& aScope)
 {
   if (mShuttingDown) {
     return true;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    // browser shutdown
+    return true;
+  }
 
   nsCOMPtr<nsIPrincipal> principal = PrincipalInfoToPrincipal(aPrincipalInfo);
   if (NS_WARN_IF(!principal)) {
     return true;
   }
 
   nsresult rv = swm->NotifyUnregister(principal, aScope);
   Unused << NS_WARN_IF(NS_FAILED(rv));
@@ -70,31 +75,33 @@ ServiceWorkerManagerChild::RecvNotifyUnr
 bool
 ServiceWorkerManagerChild::RecvNotifyRemove(const nsCString& aHost)
 {
   if (mShuttingDown) {
     return true;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (swm) {
+    swm->Remove(aHost);
+  }
 
-  swm->Remove(aHost);
   return true;
 }
 
 bool
 ServiceWorkerManagerChild::RecvNotifyRemoveAll()
 {
   if (mShuttingDown) {
     return true;
   }
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (swm) {
+    swm->RemoveAll();
+  }
 
-  swm->RemoveAll();
   return true;
 }
 
 } // namespace workers
 } // namespace dom
 } // namespace mozilla
--- a/dom/workers/ServiceWorkerPrivate.cpp
+++ b/dom/workers/ServiceWorkerPrivate.cpp
@@ -1613,23 +1613,21 @@ ServiceWorkerPrivate::SendFetchEvent(nsI
     NewRunnableMethod(aChannel, &nsIInterceptedChannel::ResetInterception);
 
   nsresult rv = SpawnWorkerIfNeeded(FetchEvent, failRunnable, aLoadGroup);
   NS_ENSURE_SUCCESS(rv, rv);
 
   nsMainThreadPtrHandle<nsIInterceptedChannel> handle(
     new nsMainThreadPtrHolder<nsIInterceptedChannel>(aChannel, false));
 
-  if (NS_WARN_IF(!mInfo)) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (NS_WARN_IF(!mInfo || !swm)) {
     return NS_ERROR_FAILURE;
   }
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
-
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     swm->GetRegistration(mInfo->GetPrincipal(), mInfo->Scope());
 
   // Its possible the registration is removed between starting the interception
   // and actually dispatching the fetch event.  In these cases we simply
   // want to restart the original network request.  Since this is a normal
   // condition we handle the reset here instead of returning an error which
   // would in turn trigger a console report.
--- a/dom/workers/ServiceWorkerRegisterJob.cpp
+++ b/dom/workers/ServiceWorkerRegisterJob.cpp
@@ -21,22 +21,22 @@ ServiceWorkerRegisterJob::ServiceWorkerR
 {
 }
 
 void
 ServiceWorkerRegisterJob::AsyncExecute()
 {
   AssertIsOnMainThread();
 
-  if (Canceled()) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (Canceled() || !swm) {
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     swm->GetRegistration(mPrincipal, mScope);
 
   if (registration) {
     // If we are resurrecting an uninstalling registration, then persist
     // it to disk again.  We preemptively removed it earlier during
     // unregister so that closing the window by shutting down the browser
     // results in the registration being gone on restart.
--- a/dom/workers/ServiceWorkerRegistration.cpp
+++ b/dom/workers/ServiceWorkerRegistration.cpp
@@ -340,17 +340,20 @@ UpdateInternal(nsIPrincipal* aPrincipal,
                const nsAString& aScope,
                ServiceWorkerUpdateFinishCallback* aCallback)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aPrincipal);
   MOZ_ASSERT(aCallback);
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-  MOZ_ASSERT(swm);
+  if (!swm) {
+    // browser shutdown
+    return;
+  }
 
   swm->Update(aPrincipal, NS_ConvertUTF16toUTF8(aScope), aCallback);
 }
 
 class MainThreadUpdateCallback final : public ServiceWorkerUpdateFinishCallback
 {
   RefPtr<Promise> mPromise;
 
--- a/dom/workers/ServiceWorkerRegistrationInfo.cpp
+++ b/dom/workers/ServiceWorkerRegistrationInfo.cpp
@@ -231,21 +231,26 @@ ServiceWorkerRegistrationInfo::TryToActi
 
 void
 ServiceWorkerRegistrationInfo::Activate()
 {
   if (!mWaitingWorker) {
     return;
   }
 
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm) {
+    // browser shutdown began during async activation step
+    return;
+  }
+
   TransitionWaitingToActive();
 
   // FIXME(nsm): Unlink appcache if there is one.
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   swm->CheckPendingReadyPromises();
 
   // "Queue a task to fire a simple event named controllerchange..."
   nsCOMPtr<nsIRunnable> controllerChangeRunnable =
     NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
       swm, &ServiceWorkerManager::FireControllerChange, this);
   NS_DispatchToMainThread(controllerChangeRunnable);
 
@@ -274,16 +279,20 @@ ServiceWorkerRegistrationInfo::FinishAct
   if (mPendingUninstall || !mActiveWorker ||
       mActiveWorker->State() != ServiceWorkerState::Activating) {
     return;
   }
 
   // Activation never fails, so aSuccess is ignored.
   mActiveWorker->UpdateState(ServiceWorkerState::Activated);
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm) {
+    // browser shutdown started during async activation completion step
+    return;
+  }
   swm->StoreRegistration(mPrincipal, this);
 }
 
 void
 ServiceWorkerRegistrationInfo::RefreshLastUpdateCheckTime()
 {
   AssertIsOnMainThread();
   mLastUpdateCheckTime = PR_IntervalNow() / PR_MSEC_PER_SEC;
@@ -312,16 +321,21 @@ void
 ServiceWorkerRegistrationInfo::NotifyListenersOnChange(WhichServiceWorker aChangedWorkers)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aChangedWorkers & (WhichServiceWorker::INSTALLING_WORKER |
                                 WhichServiceWorker::WAITING_WORKER |
                                 WhichServiceWorker::ACTIVE_WORKER));
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm) {
+    // browser shutdown started
+    return;
+  }
+
   swm->InvalidateServiceWorkerRegistrationWorker(this, aChangedWorkers);
 
   nsTArray<nsCOMPtr<nsIServiceWorkerRegistrationInfoListener>> listeners(mListeners);
   for (size_t index = 0; index < listeners.Length(); ++index) {
     listeners[index]->OnChange();
   }
 }
 
@@ -465,16 +479,20 @@ ServiceWorkerRegistrationInfo::Transitio
   }
 
   mWaitingWorker = mInstallingWorker.forget();
   mWaitingWorker->UpdateState(ServiceWorkerState::Installed);
   NotifyListenersOnChange(WhichServiceWorker::INSTALLING_WORKER |
                           WhichServiceWorker::WAITING_WORKER);
 
   RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (!swm) {
+    // browser shutdown began
+    return;
+  }
   swm->StoreRegistration(mPrincipal, this);
 }
 
 void
 ServiceWorkerRegistrationInfo::SetActive(ServiceWorkerInfo* aServiceWorker)
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(aServiceWorker);
--- a/dom/workers/ServiceWorkerUnregisterJob.cpp
+++ b/dom/workers/ServiceWorkerUnregisterJob.cpp
@@ -94,28 +94,27 @@ ServiceWorkerUnregisterJob::AsyncExecute
   }
 }
 
 void
 ServiceWorkerUnregisterJob::Unregister()
 {
   AssertIsOnMainThread();
 
-  if (Canceled()) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (Canceled() || !swm) {
     Finish(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
   // Step 1 of the Unregister algorithm requires checking that the
   // client origin matches the scope's origin.  We perform this in
   // registration->update() method directly since we don't have that
   // client information available here.
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
   // "Let registration be the result of running [[Get Registration]]
   // algorithm passing scope as the argument."
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     swm->GetRegistration(mPrincipal, mScope);
   if (!registration) {
     // "If registration is null, then, resolve promise with false."
     Finish(NS_OK);
     return;
--- a/dom/workers/ServiceWorkerUpdateJob.cpp
+++ b/dom/workers/ServiceWorkerUpdateJob.cpp
@@ -232,26 +232,26 @@ ServiceWorkerUpdateJob::FailUpdateJob(ns
 }
 
 void
 ServiceWorkerUpdateJob::AsyncExecute()
 {
   AssertIsOnMainThread();
   MOZ_ASSERT(GetType() == Type::Update);
 
-  if (Canceled()) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (Canceled() || !swm) {
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
   // Begin step 1 of the Update algorithm.
   //
   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#update-algorithm
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
   RefPtr<ServiceWorkerRegistrationInfo> registration =
     swm->GetRegistration(mPrincipal, mScope);
 
   if (!registration || registration->mPendingUninstall) {
     ErrorResult rv;
     rv.ThrowTypeError<MSG_SW_UPDATE_BAD_REGISTRATION>(NS_ConvertUTF8toUTF16(mScope),
                                                       NS_LITERAL_STRING("uninstalled"));
     FailUpdateJob(rv);
@@ -321,17 +321,18 @@ ServiceWorkerUpdateJob::Update()
 void
 ServiceWorkerUpdateJob::ComparisonResult(nsresult aStatus,
                                          bool aInCacheAndEqual,
                                          const nsAString& aNewCacheName,
                                          const nsACString& aMaxScope)
 {
   AssertIsOnMainThread();
 
-  if (NS_WARN_IF(Canceled())) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (NS_WARN_IF(Canceled() || !swm)) {
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
   // Handle failure of the download or comparison.  This is part of Update
   // step 5 as "If the algorithm asynchronously completes with null, then:".
   if (NS_WARN_IF(NS_FAILED(aStatus))) {
     FailUpdateJob(aStatus);
@@ -386,17 +387,16 @@ ServiceWorkerUpdateJob::ComparisonResult
     NS_ConvertUTF8toUTF16 reportScope(mRegistration->mScope);
     NS_ConvertUTF8toUTF16 reportMaxPrefix(maxPrefix);
     const char16_t* params[] = { reportScope.get(), reportMaxPrefix.get() };
 
     rv = nsContentUtils::FormatLocalizedString(nsContentUtils::eDOM_PROPERTIES,
                                                "ServiceWorkerScopePathMismatch",
                                                params, message);
     NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Failed to format localized string");
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
     swm->ReportToAllClients(mScope,
                             message,
                             EmptyString(),
                             EmptyString(), 0, 0,
                             nsIScriptError::errorFlag);
     FailUpdateJob(NS_ERROR_DOM_SECURITY_ERR);
     return;
   }
@@ -433,17 +433,18 @@ ServiceWorkerUpdateJob::ComparisonResult
   }
 }
 
 void
 ServiceWorkerUpdateJob::ContinueUpdateAfterScriptEval(bool aScriptEvaluationResult)
 {
   AssertIsOnMainThread();
 
-  if (Canceled()) {
+  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+  if (Canceled() || !swm) {
     FailUpdateJob(NS_ERROR_DOM_ABORT_ERR);
     return;
   }
 
   // Step 7.5 of the Update algorithm verifying that the script evaluated
   // successfully.
 
   if (NS_WARN_IF(!aScriptEvaluationResult)) {
@@ -451,45 +452,44 @@ ServiceWorkerUpdateJob::ContinueUpdateAf
 
     NS_ConvertUTF8toUTF16 scriptSpec(mScriptSpec);
     NS_ConvertUTF8toUTF16 scope(mRegistration->mScope);
     error.ThrowTypeError<MSG_SW_SCRIPT_THREW>(scriptSpec, scope);
     FailUpdateJob(error);
     return;
   }
 
-  Install();
+  Install(swm);
 }
 
 void
-ServiceWorkerUpdateJob::Install()
+ServiceWorkerUpdateJob::Install(ServiceWorkerManager* aSWM)
 {
   AssertIsOnMainThread();
-  MOZ_ASSERT(!Canceled());
+  MOZ_DIAGNOSTIC_ASSERT(!Canceled());
+  MOZ_DIAGNOSTIC_ASSERT(aSWM);
 
   MOZ_ASSERT(!mRegistration->GetInstalling());
 
   // Begin step 2 of the Install algorithm.
   //
   //  https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#installation-algorithm
 
   mRegistration->TransitionEvaluatingToInstalling();
 
   // Step 6 of the Install algorithm resolving the job promise.
   InvokeResultCallbacks(NS_OK);
 
   // The job promise cannot be rejected after this point, but the job can
   // still fail; e.g. if the install event handler throws, etc.
 
-  RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-
   // fire the updatefound event
   nsCOMPtr<nsIRunnable> upr =
     NewRunnableMethod<RefPtr<ServiceWorkerRegistrationInfo>>(
-      swm,
+      aSWM,
       &ServiceWorkerManager::FireUpdateFoundOnServiceWorkerRegistrations,
       mRegistration);
   NS_DispatchToMainThread(upr);
 
   // Call ContinueAfterInstallEvent(false) on main thread if the SW
   // script fails to load.
   nsCOMPtr<nsIRunnable> failRunnable = NewRunnableMethod<bool>
     (this, &ServiceWorkerUpdateJob::ContinueAfterInstallEvent, false);
--- a/dom/workers/ServiceWorkerUpdateJob.h
+++ b/dom/workers/ServiceWorkerUpdateJob.h
@@ -8,16 +8,18 @@
 #define mozilla_dom_workers_serviceworkerupdatejob_h
 
 #include "ServiceWorkerJob.h"
 
 namespace mozilla {
 namespace dom {
 namespace workers {
 
+class ServiceWorkerManager;
+
 // A job class that performs the Update and Install algorithms from the
 // service worker spec.  This class is designed to be inherited and customized
 // as a different job type.  This is necessary because the register job
 // performs largely the same operations as the update job, but has a few
 // different starting steps.
 class ServiceWorkerUpdateJob : public ServiceWorkerJob
 {
 public:
@@ -80,17 +82,17 @@ private:
                    const nsACString& aMaxScope);
 
   // Utility method called after evaluating the worker script.
   void
   ContinueUpdateAfterScriptEval(bool aScriptEvaluationResult);
 
   // Utility method corresponding to the spec Install algorithm.
   void
-  Install();
+  Install(ServiceWorkerManager* aSWM);
 
   // Utility method called after the install event is handled.
   void
   ContinueAfterInstallEvent(bool aInstallEventSuccess);
 
   nsCOMPtr<nsILoadGroup> mLoadGroup;
   RefPtr<ServiceWorkerRegistrationInfo> mRegistration;
 };
--- a/dom/workers/WorkerPrivate.cpp
+++ b/dom/workers/WorkerPrivate.cpp
@@ -1175,23 +1175,24 @@ private:
         return true;
       }
 
       // Service workers do not have a main thread parent global, so normal
       // worker error reporting will crash.  Instead, pass the error to
       // the ServiceWorkerManager to report on any controlled documents.
       if (aWorkerPrivate->IsServiceWorker()) {
         RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-        MOZ_ASSERT(swm);
-        swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
-                         aWorkerPrivate->WorkerName(),
-                         aWorkerPrivate->ScriptURL(),
-                         mMessage,
-                         mFilename, mLine, mLineNumber,
-                         mColumnNumber, mFlags, mExnType);
+        if (swm) {
+          swm->HandleError(aCx, aWorkerPrivate->GetPrincipal(),
+                           aWorkerPrivate->WorkerName(),
+                           aWorkerPrivate->ScriptURL(),
+                           mMessage,
+                           mFilename, mLine, mLineNumber,
+                           mColumnNumber, mFlags, mExnType);
+        }
         return true;
       }
 
       // The innerWindowId is only required if we are going to ReportError
       // below, which is gated on this condition. The inner window correctness
       // check is only going to succeed when the worker is accepting events.
       if (workerIsAcceptingEvents) {
         aWorkerPrivate->AssertInnerWindowIsCorrect();
--- a/dom/workers/WorkerScope.cpp
+++ b/dom/workers/WorkerScope.cpp
@@ -655,27 +655,30 @@ public:
   {
     MOZ_ASSERT(aPromiseProxy);
   }
 
   NS_IMETHOD
   Run() override
   {
     AssertIsOnMainThread();
-    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
-    MOZ_ASSERT(swm);
 
     MutexAutoLock lock(mPromiseProxy->Lock());
     if (mPromiseProxy->CleanedUp()) {
       return NS_OK;
     }
 
     WorkerPrivate* workerPrivate = mPromiseProxy->GetWorkerPrivate();
-    swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope,
-                            workerPrivate->ServiceWorkerID());
+    MOZ_DIAGNOSTIC_ASSERT(workerPrivate);
+
+    RefPtr<ServiceWorkerManager> swm = ServiceWorkerManager::GetInstance();
+    if (swm) {
+      swm->SetSkipWaitingFlag(workerPrivate->GetPrincipal(), mScope,
+                              workerPrivate->ServiceWorkerID());
+    }
 
     RefPtr<SkipWaitingResultRunnable> runnable =
       new SkipWaitingResultRunnable(workerPrivate, mPromiseProxy);
 
     if (!runnable->Dispatch()) {
       NS_WARNING("Failed to dispatch SkipWaitingResultRunnable to the worker.");
     }
     return NS_OK;