aboutsummaryrefslogtreecommitdiff
path: root/www/waterfox/files/patch-bug1425930
blob: ca6d6af5e015e73f3493315a9a1eb212428197d0 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
commit dc0965023fb7
Author: Randell Jesup <rjesup@jesup.org>
Date:   Mon May 21 15:30:35 2018 -0400

    Bug 1425930 - Handle Broadcast()->Notify() calling RemoveObserver(). r=froydnj, a=abillings
    
    --HG--
    extra : source : a314710b0acd38afc7de74f0306f514b50d84463
---
 xpcom/ds/Observer.h | 28 ++++++++++++++++++++++++----
 1 file changed, 24 insertions(+), 4 deletions(-)

diff --git xpcom/ds/Observer.h xpcom/ds/Observer.h
index 958e5e4a9694e..83d650a936ccc 100644
--- xpcom/ds/Observer.h
+++ xpcom/ds/Observer.h
@@ -57,7 +57,17 @@ public:
    */
   bool RemoveObserver(Observer<T>* 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<Observer<T>*> 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<Observer<T>*> mObservers;
+  nsTArray<Observer<T>*> mBroadcastCopy;
 };
 
 } // namespace mozilla