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}
This commit is contained in:
Karl Wiberg
2020-11-11 11:48:04 +01:00
committed by Commit Bot
parent b249d0a905
commit 01a36f32e7
3 changed files with 16 additions and 2 deletions

View File

@ -54,6 +54,7 @@ rtc_source_set("callback_list") {
"callback_list.h", "callback_list.h",
] ]
deps = [ deps = [
":checks",
":untyped_function", ":untyped_function",
"../api:function_view", "../api:function_view",
"system:assume", "system:assume",

View File

@ -10,17 +10,25 @@
#include "rtc_base/callback_list.h" #include "rtc_base/callback_list.h"
#include "rtc_base/checks.h"
namespace webrtc { namespace webrtc {
namespace callback_list_impl { namespace callback_list_impl {
CallbackListReceivers::CallbackListReceivers() = default; CallbackListReceivers::CallbackListReceivers() = default;
CallbackListReceivers::~CallbackListReceivers() = default;
CallbackListReceivers::~CallbackListReceivers() {
RTC_CHECK(!send_in_progress_);
}
void CallbackListReceivers::Foreach( void CallbackListReceivers::Foreach(
rtc::FunctionView<void(UntypedFunction&)> fv) { rtc::FunctionView<void(UntypedFunction&)> fv) {
RTC_CHECK(!send_in_progress_);
send_in_progress_ = true;
for (auto& r : receivers_) { for (auto& r : receivers_) {
fv(r); fv(r);
} }
send_in_progress_ = false;
} }
template void CallbackListReceivers::AddReceiver( template void CallbackListReceivers::AddReceiver(

View File

@ -15,6 +15,7 @@
#include <vector> #include <vector>
#include "api/function_view.h" #include "api/function_view.h"
#include "rtc_base/checks.h"
#include "rtc_base/system/assume.h" #include "rtc_base/system/assume.h"
#include "rtc_base/system/inline.h" #include "rtc_base/system/inline.h"
#include "rtc_base/untyped_function.h" #include "rtc_base/untyped_function.h"
@ -33,6 +34,7 @@ class CallbackListReceivers {
template <typename UntypedFunctionArgsT> template <typename UntypedFunctionArgsT>
RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) { RTC_NO_INLINE void AddReceiver(UntypedFunctionArgsT args) {
RTC_CHECK(!send_in_progress_);
receivers_.push_back(UntypedFunction::Create(args)); receivers_.push_back(UntypedFunction::Create(args));
} }
@ -40,6 +42,7 @@ class CallbackListReceivers {
private: private:
std::vector<UntypedFunction> receivers_; std::vector<UntypedFunction> receivers_;
bool send_in_progress_ = false;
}; };
extern template void CallbackListReceivers::AddReceiver( extern template void CallbackListReceivers::AddReceiver(
@ -145,7 +148,9 @@ class CallbackList {
UntypedFunction::PrepareArgs<void(ArgT...)>(std::forward<F>(f))); 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> template <typename... ArgU>
void Send(ArgU&&... args) { void Send(ArgU&&... args) {
receivers_.Foreach([&](UntypedFunction& f) { receivers_.Foreach([&](UntypedFunction& f) {