CallbackList: Don't allow reentrancy

When a Send is in progress, don't allow modification to the list of
callbacks, or a recursive Send.

Bug: webrtc:11943
Change-Id: I88751060136972d0c9170db725fa30312a14b5b1
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/192360
Commit-Queue: Karl Wiberg <kwiberg@webrtc.org>
Reviewed-by: Niels Moller <nisse@webrtc.org>
Reviewed-by: Markus Handell <handellm@webrtc.org>
Cr-Commit-Position: refs/heads/master@{#32584}
diff --git a/rtc_base/BUILD.gn b/rtc_base/BUILD.gn
index a4d209e..6ee7190 100644
--- a/rtc_base/BUILD.gn
+++ b/rtc_base/BUILD.gn
@@ -54,6 +54,7 @@
     "callback_list.h",
   ]
   deps = [
+    ":checks",
     ":untyped_function",
     "../api:function_view",
     "system:assume",
diff --git a/rtc_base/callback_list.cc b/rtc_base/callback_list.cc
index 0b1de8e..ac947e2 100644
--- a/rtc_base/callback_list.cc
+++ b/rtc_base/callback_list.cc
@@ -10,17 +10,25 @@
 
 #include "rtc_base/callback_list.h"
 
+#include "rtc_base/checks.h"
+
 namespace webrtc {
 namespace callback_list_impl {
 
 CallbackListReceivers::CallbackListReceivers() = default;
-CallbackListReceivers::~CallbackListReceivers() = default;
+
+CallbackListReceivers::~CallbackListReceivers() {
+  RTC_CHECK(!send_in_progress_);
+}
 
 void CallbackListReceivers::Foreach(
     rtc::FunctionView<void(UntypedFunction&)> fv) {
+  RTC_CHECK(!send_in_progress_);
+  send_in_progress_ = true;
   for (auto& r : receivers_) {
     fv(r);
   }
+  send_in_progress_ = false;
 }
 
 template void CallbackListReceivers::AddReceiver(
diff --git a/rtc_base/callback_list.h b/rtc_base/callback_list.h
index 59da8ee..659b838 100644
--- a/rtc_base/callback_list.h
+++ b/rtc_base/callback_list.h
@@ -15,6 +15,7 @@
 #include <vector>
 
 #include "api/function_view.h"
+#include "rtc_base/checks.h"
 #include "rtc_base/system/assume.h"
 #include "rtc_base/system/inline.h"
 #include "rtc_base/untyped_function.h"
@@ -33,6 +34,7 @@
 
   template <typename UntypedFunctionArgsT>
   RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
+    RTC_CHECK(!send_in_progress_);
     receivers_.push_back(UntypedFunction::Create(args));
   }
 
@@ -40,6 +42,7 @@
 
  private:
   std::vector<UntypedFunction> receivers_;
+  bool send_in_progress_ = false;
 };
 
 extern template void CallbackListReceivers::AddReceiver(
@@ -145,7 +148,9 @@
         UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f)));
   }
 
-  // Calls all receivers with the given arguments.
+  // Calls all receivers with the given arguments. While the Send is in
+  // progress, no method calls are allowed; specifically, this means that the
+  // callbacks may not do anything with this CallbackList instance.
   template <typename... ArgU>
   void Send(ArgU&&... args) {
     receivers_.Foreach([&](UntypedFunction& f) {