From 27aae0dbebb876e7c1b77ab1db20e9fe992d2571 Mon Sep 17 00:00:00 2001 From: Randell Jesup Date: Mon, 21 May 2018 15:30:35 -0400 Subject: [PATCH] Bug 1425930: Handle Broadcast()->Notify() calling RemoveObserver() r=froyd --- xpcom/ds/Observer.h | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/xpcom/ds/Observer.h b/xpcom/ds/Observer.h index 958e5e4a9694..83d650a936cc 100644 --- a/xpcom/ds/Observer.h +++ b/xpcom/ds/Observer.h @@ -57,7 +57,17 @@ public: */ bool RemoveObserver(Observer* aObserver) { - return mObservers.RemoveElement(aObserver); + if (mObservers.RemoveElement(aObserver)) { + if (!mBroadcastCopy.IsEmpty()) { + // Annoyingly, someone could RemoveObserver() an item on the list + // while we're in a Broadcast()'s Notify() call. + auto i = mBroadcastCopy.IndexOf(aObserver); + MOZ_ASSERT(i != mBroadcastCopy.NoIndex); + mBroadcastCopy[i] = nullptr; + } + return true; + } + return false; } uint32_t Length() @@ -65,17 +75,27 @@ public: return mObservers.Length(); } + /** + * Call Notify() on each item in the list. + * Handles the case of Notify() calling RemoveObserver() + */ void Broadcast(const T& aParam) { - nsTArray*> observersCopy(mObservers); - uint32_t size = observersCopy.Length(); + MOZ_ASSERT(mBroadcastCopy.IsEmpty()); + mBroadcastCopy = mObservers; + uint32_t size = mBroadcastCopy.Length(); for (uint32_t i = 0; i < size; ++i) { - observersCopy[i]->Notify(aParam); + // nulled if Removed during Broadcast + if (mBroadcastCopy[i]) { + mBroadcastCopy[i]->Notify(aParam); + } } + mBroadcastCopy.Clear(); } protected: nsTArray*> mObservers; + nsTArray*> mBroadcastCopy; }; } // namespace mozilla