Bug 668245 - r=bz, a=LegNeato
authorMarco Bonardo <mbonardo@mozilla.com>
Wed, 13 Jul 2011 14:28:37 -0700
changeset 70543 37dc24eeac59702a08d6107135b5a4e96ac8af21
parent 70542 e05336fe9f4ff5a6f72cd6ec79d17cc84af54f85
child 70544 79f80d48e0d3d76a36e284a77738ba085f0734c1
push id1
push usersledru@mozilla.com
push dateThu, 04 Dec 2014 17:57:20 +0000
reviewersbz, LegNeato
bugs668245
milestone6.0
Bug 668245 - r=bz, a=LegNeato
toolkit/components/places/History.cpp
toolkit/components/places/History.h
--- a/toolkit/components/places/History.cpp
+++ b/toolkit/components/places/History.cpp
@@ -51,16 +51,17 @@
 #include "mozilla/storage.h"
 #include "mozilla/dom/Link.h"
 #include "nsDocShellCID.h"
 #include "mozilla/Services.h"
 #include "nsThreadUtils.h"
 #include "nsNetUtil.h"
 #include "nsIXPConnect.h"
 #include "mozilla/Util.h"
+#include "nsContentUtils.h"
 
 // Initial size for the cache holding visited status observers.
 #define VISIT_OBSERVERS_INITIAL_CACHE_SIZE 128
 
 // Topic used to notify that work in mozIAsyncHistory::updatePlaces is done.
 #define TOPIC_UPDATEPLACES_COMPLETE "places-updatePlaces-complete"
 
 using namespace mozilla::dom;
@@ -1269,16 +1270,18 @@ History::~History()
 #endif
 }
 
 void
 History::NotifyVisited(nsIURI* aURI)
 {
   NS_ASSERTION(aURI, "Ruh-roh!  A NULL URI was passed to us!");
 
+  nsAutoScriptBlocker scriptBlocker;
+
   if (XRE_GetProcessType() == GeckoProcessType_Default) {
     mozilla::dom::ContentParent* cpp = 
       mozilla::dom::ContentParent::GetSingleton(PR_FALSE);
     if (cpp)
       (void)cpp->SendNotifyVisited(aURI);
   }
 
   // If the hash table has not been initialized, then we have nothing to notify
@@ -1289,24 +1292,28 @@ History::NotifyVisited(nsIURI* aURI)
 
   // Additionally, if we have no observers for this URI, we have nothing to
   // notify about.
   KeyClass* key = mObservers.GetEntry(aURI);
   if (!key) {
     return;
   }
 
-  // Walk through the array, and update each Link node.
-  const ObserverArray& observers = key->array;
-  ObserverArray::index_type len = observers.Length();
-  for (ObserverArray::index_type i = 0; i < len; i++) {
-    Link* link = observers[i];
-    link->SetLinkState(eLinkState_Visited);
-    NS_ASSERTION(len == observers.Length(),
-                 "Calling SetLinkState added or removed an observer!");
+  // Update status of each Link node.
+  {
+    // RemoveEntry will destroy the array, this iterator should not survive it.
+    ObserverArray::ForwardIterator iter(key->array);
+    while (iter.HasMore()) {
+      Link* link = iter.GetNext();
+      link->SetLinkState(eLinkState_Visited);
+      // Verify that the observers hash doesn't mutate while looping through
+      // the links associated with this URI.
+      NS_ABORT_IF_FALSE(key == mObservers.GetEntry(aURI),
+                        "The URIs hash mutated!");
+    }
   }
 
   // All the registered nodes can now be removed for this URI.
   mObservers.RemoveEntry(aURI);
 }
 
 mozIStorageAsyncStatement*
 History::GetIsVisitedStatement()
--- a/toolkit/components/places/History.h
+++ b/toolkit/components/places/History.h
@@ -41,17 +41,17 @@
 #define mozilla_places_History_h_
 
 #include "mozilla/IHistory.h"
 #include "mozIAsyncHistory.h"
 #include "mozilla/dom/Link.h"
 #include "nsTHashtable.h"
 #include "nsString.h"
 #include "nsURIHashKey.h"
-#include "nsTArray.h"
+#include "nsTObserverArray.h"
 #include "nsDeque.h"
 #include "nsIObserver.h"
 #include "mozIStorageConnection.h"
 #include "mozilla/storage/StatementCache.h"
 
 namespace mozilla {
 namespace places {
 
@@ -162,17 +162,17 @@ private:
    */
   void Shutdown();
 
   static History* gService;
 
   // Ensures new tasks aren't started on destruction.
   bool mShuttingDown;
 
-  typedef nsTArray<mozilla::dom::Link* > ObserverArray;
+  typedef nsTObserverArray<mozilla::dom::Link* > ObserverArray;
 
   class KeyClass : public nsURIHashKey
   {
   public:
     KeyClass(const nsIURI* aURI)
     : nsURIHashKey(aURI)
     {
     }