[MainLoop] Fix possible use of an invalid iterator

Store file descriptors from loop.m_read_fds (if FORCE_PSELECT is
defined) and signals from loop.m_signals that need to be processed in
MainLoop::RunImpl::ProcessEvents() into a separate vector and then
iterate over this container to invoke the callbacks.

This prevents a problem where when the code iterated directly over
m_read_fds/m_signals, a callback invoked from within the loop could
modify these variables and invalidate the loop iterator. This would then
result in an assertion failure in llvm::DenseMapIterator::operator++().

Differential Revision: https://reviews.llvm.org/D35298

llvm-svn: 307782
This commit is contained in:
Petr Pavlu 2017-07-12 12:38:31 +00:00
parent 293b4fc04e
commit 8c5dafde49
1 changed files with 18 additions and 9 deletions

View File

@ -193,10 +193,16 @@ Status MainLoop::RunImpl::Poll() {
void MainLoop::RunImpl::ProcessEvents() {
#ifdef FORCE_PSELECT
for (const auto &fd : loop.m_read_fds) {
if (!FD_ISSET(fd.first, &read_fd_set))
continue;
IOObject::WaitableHandle handle = fd.first;
// Collect first all readable file descriptors into a separate vector and then
// iterate over it to invoke callbacks. Iterating directly over
// loop.m_read_fds is not possible because the callbacks can modify the
// container which could invalidate the iterator.
std::vector<IOObject::WaitableHandle> fds;
for (const auto &fd : loop.m_read_fds)
if (FD_ISSET(fd.first, &read_fd_set))
fds.push_back(fd.first);
for (const auto &handle : fds) {
#else
for (const auto &fd : read_fds) {
if ((fd.revents & POLLIN) == 0)
@ -209,13 +215,16 @@ void MainLoop::RunImpl::ProcessEvents() {
loop.ProcessReadObject(handle);
}
for (const auto &entry : loop.m_signals) {
std::vector<int> signals;
for (const auto &entry : loop.m_signals)
if (g_signal_flags[entry.first] != 0)
signals.push_back(entry.first);
for (const auto &signal : signals) {
if (loop.m_terminate_request)
return;
if (g_signal_flags[entry.first] == 0)
continue; // No signal
g_signal_flags[entry.first] = 0;
loop.ProcessSignal(entry.first);
g_signal_flags[signal] = 0;
loop.ProcessSignal(signal);
}
}
#endif