Bug 1548847 - Invalidate LSDatabase xpcom-shutdown observer after removing it from the observer service; r=asuth
authorJan Varga <jan.varga@gmail.com>
Wed, 15 May 2019 19:35:22 +0200
changeset 474164 78f167160710f9aca6a6d805851a04d267c24590
parent 474163 673d845734b2ebacb3a9ddd68f58f39a61eb9a41
child 474165 dd5c42327e22e7de29060c6a37a550401a8bf9fb
push id36023
push userncsoregi@mozilla.com
push dateThu, 16 May 2019 21:56:43 +0000
treeherdermozilla-central@786f094a30ae [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersasuth
bugs1548847
milestone68.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1548847 - Invalidate LSDatabase xpcom-shutdown observer after removing it from the observer service; r=asuth Differential Revision: https://phabricator.services.mozilla.com/D31293
dom/localstorage/LSDatabase.cpp
--- a/dom/localstorage/LSDatabase.cpp
+++ b/dom/localstorage/LSDatabase.cpp
@@ -19,18 +19,22 @@ typedef nsDataHashtable<nsCStringHashKey
 
 StaticAutoPtr<LSDatabaseHashtable> gLSDatabases;
 
 }  // namespace
 
 StaticRefPtr<LSDatabase::Observer> LSDatabase::sObserver;
 
 class LSDatabase::Observer final : public nsIObserver {
+  bool mInvalidated;
+
  public:
-  Observer() { MOZ_ASSERT(NS_IsMainThread()); }
+  Observer() : mInvalidated(false) { MOZ_ASSERT(NS_IsMainThread()); }
+
+  void Invalidate() { mInvalidated = true; }
 
  private:
   ~Observer() { MOZ_ASSERT(NS_IsMainThread()); }
 
   NS_DECL_ISUPPORTS
   NS_DECL_NSIOBSERVER
 };
 
@@ -350,27 +354,39 @@ void LSDatabase::AllowToClose() {
     MOZ_ASSERT(sObserver);
 
     nsCOMPtr<nsIObserverService> obsSvc = GetObserverService();
     MOZ_ASSERT(obsSvc);
 
     MOZ_ALWAYS_SUCCEEDS(
         obsSvc->RemoveObserver(sObserver, XPCOM_SHUTDOWN_OBSERVER_TOPIC));
 
+    // We also need to invalidate the observer because AllowToClose can be
+    // triggered by an indirectly related observer, so the observer service
+    // may still keep our observer alive and call Observe on it. This is
+    // possible because observer service snapshots the observer list for given
+    // subject before looping over the list.
+    sObserver->Invalidate();
+
     sObserver = nullptr;
   }
 }
 
 NS_IMPL_ISUPPORTS(LSDatabase::Observer, nsIObserver)
 
 NS_IMETHODIMP
 LSDatabase::Observer::Observe(nsISupports* aSubject, const char* aTopic,
                               const char16_t* aData) {
   MOZ_ASSERT(NS_IsMainThread());
   MOZ_ASSERT(!strcmp(aTopic, XPCOM_SHUTDOWN_OBSERVER_TOPIC));
+
+  if (mInvalidated) {
+    return NS_OK;
+  }
+
   MOZ_ASSERT(gLSDatabases);
 
   nsTArray<RefPtr<LSDatabase>> databases;
 
   for (auto iter = gLSDatabases->ConstIter(); !iter.Done(); iter.Next()) {
     LSDatabase* database = iter.Data();
     MOZ_ASSERT(database);