Bug 1150916 - Be sure we aren't iterating over a hashtable while it is modified in nsObserverService::UnmarkGrayStrongObservers(). r=froydnj

The QI in xpc_TryUnmarkWrappedGrayObject() might somehow trigger a GC,
which in turn could destroy an observer, that would in turn call
RemoveObserver() which mutates the hash table that we're enumerating.
This commit is contained in:
Andrew McCreight 2015-04-08 17:16:30 -07:00
parent 1379ac68ce
commit c52fe26c5b
3 changed files with 26 additions and 18 deletions

View File

@ -88,6 +88,18 @@ nsObserverList::FillObserverArray(nsCOMArray<nsIObserver>& aArray)
}
}
void
nsObserverList::AppendStrongObservers(nsCOMArray<nsIObserver>& aArray)
{
aArray.SetCapacity(aArray.Length() + mObservers.Length());
for (int32_t i = mObservers.Length() - 1; i >= 0; --i) {
if (!mObservers[i].isWeakRef) {
aArray.AppendObject(mObservers[i].asObserver());
}
}
}
void
nsObserverList::NotifyObservers(nsISupports* aSubject,
const char* aTopic,
@ -101,18 +113,6 @@ nsObserverList::NotifyObservers(nsISupports* aSubject,
}
}
void
nsObserverList::UnmarkGrayStrongObservers()
{
#if !defined(MOZILLA_XPCOMRT_API)
for (uint32_t i = 0; i < mObservers.Length(); ++i) {
if (!mObservers[i].isWeakRef) {
xpc_TryUnmarkWrappedGrayObject(mObservers[i].asObserver());
}
}
#endif // !defined(MOZILLA_XPCOMRT_API)
}
NS_IMPL_ISUPPORTS(nsObserverEnumerator, nsISimpleEnumerator)
nsObserverEnumerator::nsObserverEnumerator(nsObserverList* aObserverList)

View File

@ -71,9 +71,8 @@ public:
// The array is filled in last-added-first order.
void FillObserverArray(nsCOMArray<nsIObserver>& aArray);
// Unmark any strongly held observers implemented in JS so the cycle
// collector will not traverse them.
void UnmarkGrayStrongObservers();
// Like FillObserverArray(), but only for strongly held observers.
void AppendStrongObservers(nsCOMArray<nsIObserver>& aArray);
private:
nsTArray<ObserverRef> mObservers;

View File

@ -344,10 +344,12 @@ NS_IMETHODIMP nsObserverService::NotifyObservers(nsISupports* aSubject,
}
static PLDHashOperator
UnmarkGrayObserverEntry(nsObserverList* aObserverList, void* aClosure)
AppendStrongObservers(nsObserverList* aObserverList, void* aClosure)
{
nsCOMArray<nsIObserver>* array = static_cast<nsCOMArray<nsIObserver>*>(aClosure);
if (aObserverList) {
aObserverList->UnmarkGrayStrongObservers();
aObserverList->AppendStrongObservers(*array);
}
return PL_DHASH_NEXT;
}
@ -357,7 +359,14 @@ nsObserverService::UnmarkGrayStrongObservers()
{
NS_ENSURE_VALIDCALL
mObserverTopicTable.EnumerateEntries(UnmarkGrayObserverEntry, nullptr);
#if !defined(MOZILLA_XPCOMRT_API)
nsCOMArray<nsIObserver> strongObservers;
mObserverTopicTable.EnumerateEntries(AppendStrongObservers, &strongObservers);
for (uint32_t i = 0; i < strongObservers.Length(); ++i) {
xpc_TryUnmarkWrappedGrayObject(strongObservers[i]);
}
#endif // !defined(MOZILLA_XPCOMRT_API)
return NS_OK;
}