Bug 1376676 - Avoid a race condition where the History.cpp cloned connection may not be closed. r=asuth draft
authorMarco Bonardo <mbonardo@mozilla.com>
Mon, 24 Jul 2017 23:08:44 +0200
changeset 614759 12b4876363037c73c29435a8ad7b6c9cf8b73846
parent 614015 5928d905c0bc0b28f5488b236444c7d7991cf8d4
child 638946 b854eccb2f3f1906ed99f36ab26e8692b08fc9d0
push id70104
push usermak77@bonardo.net
push dateMon, 24 Jul 2017 22:40:38 +0000
reviewersasuth
bugs1376676
milestone56.0a1
Bug 1376676 - Avoid a race condition where the History.cpp cloned connection may not be closed. r=asuth MozReview-Commit-ID: YXmasMLBg4
toolkit/components/places/History.cpp
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -1997,25 +1997,33 @@ History::NotifyVisited(nsIURI* aURI)
   return NS_OK;
 }
 
 class ConcurrentStatementsHolder final : public mozIStorageCompletionCallback {
 public:
   NS_DECL_ISUPPORTS
 
   explicit ConcurrentStatementsHolder(mozIStorageConnection* aDBConn)
+  : mShutdownWasInvoked(false)
   {
     DebugOnly<nsresult> rv = aDBConn->AsyncClone(true, this);
     MOZ_ASSERT(NS_SUCCEEDED(rv));
   }
 
   NS_IMETHOD Complete(nsresult aStatus, nsISupports* aConnection) override {
-    if (NS_FAILED(aStatus))
+    if (NS_FAILED(aStatus)) {
       return NS_OK;
+    }
     mReadOnlyDBConn = do_QueryInterface(aConnection);
+    // It's possible Shutdown was invoked before we were handed back the
+    // cloned connection handle.
+    if (mShutdownWasInvoked) {
+      Shutdown();
+      return NS_OK;
+    }
 
     // Now we can create our cached statements.
 
     if (!mIsVisitedStatement) {
       (void)mReadOnlyDBConn->CreateAsyncStatement(NS_LITERAL_CSTRING(
         "SELECT 1 FROM moz_places h "
         "WHERE url_hash = hash(?1) AND url = ?1 AND last_visit_date NOTNULL "
       ),  getter_AddRefs(mIsVisitedStatement));
@@ -2040,36 +2048,39 @@ public:
       MOZ_ASSERT(NS_SUCCEEDED(rv));
     } else {
       DebugOnly<bool> added = mIsVisitedCallbacks.AppendObject(aCallback);
       MOZ_ASSERT(added);
     }
   }
 
   void Shutdown() {
+    mShutdownWasInvoked = true;
     if (mReadOnlyDBConn) {
       mIsVisitedCallbacks.Clear();
       DebugOnly<nsresult> rv;
       if (mIsVisitedStatement) {
         rv = mIsVisitedStatement->Finalize();
         MOZ_ASSERT(NS_SUCCEEDED(rv));
       }
       rv = mReadOnlyDBConn->AsyncClose(nullptr);
       MOZ_ASSERT(NS_SUCCEEDED(rv));
+      mReadOnlyDBConn = nullptr;
     }
   }
 
 private:
   ~ConcurrentStatementsHolder()
   {
   }
 
   nsCOMPtr<mozIStorageAsyncConnection> mReadOnlyDBConn;
   nsCOMPtr<mozIStorageAsyncStatement> mIsVisitedStatement;
   nsCOMArray<mozIStorageCompletionCallback> mIsVisitedCallbacks;
+  bool mShutdownWasInvoked;
 };
 
 NS_IMPL_ISUPPORTS(
   ConcurrentStatementsHolder
 , mozIStorageCompletionCallback
 )
 
 nsresult