Merge pull request #3925 from bjovke/timers_issue

Problem: Usage of invalidated iterator of _timers container in zmq::p…
This commit is contained in:
Simon Giesecke 2020-05-20 16:57:24 +02:00 committed by GitHub
commit 6e62fb19b4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -68,8 +68,14 @@ void zmq::poller_base_t::cancel_timer (i_poll_events *sink_, int id_)
return; return;
} }
// Timer not found. // We should generally never get here. Calling 'cancel_timer ()' on
zmq_assert (false); // an already expired or canceled timer (or even worse - on a timer which
// never existed, supplying bad sink_ and/or id_ values) does not make any
// sense.
// But in some edge cases this might happen. As described in issue #3645
// `timer_event ()` call from `execute_timers ()` might call `cancel_timer ()`
// on already canceled (deleted) timer.
// As soon as that is resolved an 'assert (false)' should be put here.
} }
uint64_t zmq::poller_base_t::execute_timers () uint64_t zmq::poller_base_t::execute_timers ()
@ -81,26 +87,31 @@ uint64_t zmq::poller_base_t::execute_timers ()
// Get the current time. // Get the current time.
const uint64_t current = _clock.now_ms (); const uint64_t current = _clock.now_ms ();
// Execute the timers that are already due. // Execute the timers that are already due.
const timers_t::iterator begin = _timers.begin ();
const timers_t::iterator end = _timers.end ();
uint64_t res = 0; uint64_t res = 0;
timers_t::iterator it = begin; timer_info_t timer_temp;
for (; it != end; ++it) { timers_t::iterator it;
// If we have to wait to execute the item, same will be true about
// all the following items (multimap is sorted). Thus we can stop do {
// checking the subsequent timers. it = _timers.begin ();
// If we have to wait to execute the item, same will be true for
// all the following items because multimap is sorted. Thus we can
// stop checking the subsequent timers.
if (it->first > current) { if (it->first > current) {
res = it->first - current; res = it->first - current;
break; break;
} }
// Trigger the timer. // Save and remove the timer because timer_event() call might delete
it->second.sink->timer_event (it->second.id); // exactly this timer and then the iterator will be invalid.
} timer_temp = it->second;
_timers.erase (it);
// Remove them from the list of active timers. // Trigger the timer.
_timers.erase (begin, it); timer_temp.sink->timer_event (timer_temp.id);
} while (!_timers.empty ());
// Return the time to wait for the next timer (at least 1ms), or 0, if // Return the time to wait for the next timer (at least 1ms), or 0, if
// there are no more timers. // there are no more timers.