Preventing the event processing from looping endlessly when an event

reraised itself during execution of its handlers.
This commit is contained in:
Robin Sommer 2016-06-14 18:10:37 -07:00
parent ddabd13097
commit 2335a62a07
6 changed files with 67 additions and 25 deletions

View file

@ -1,4 +1,10 @@
2.4-613 | 2016-06-14 18:10:37 -0700
* Preventing the event processing from looping endlessly when an
event reraised itself during execution of its handlers. (Robin
Sommer)
2.4-612 | 2016-06-14 17:42:52 -0700 2.4-612 | 2016-06-14 17:42:52 -0700
* Improved handling of 802.11 headers. (Jan Grashoefer) * Improved handling of 802.11 headers. (Jan Grashoefer)

View file

@ -1 +1 @@
2.4-612 2.4-613

View file

@ -94,26 +94,6 @@ void EventMgr::QueueEvent(Event* event)
++num_events_queued; ++num_events_queued;
} }
void EventMgr::Dispatch()
{
if ( ! head )
reporter->InternalError("EventMgr::Dispatch underflow");
Event* current = head;
head = head->NextEvent();
if ( ! head )
tail = head;
current_src = current->Source();
current_mgr = current->Mgr();
current_aid = current->Analyzer();
current->Dispatch();
Unref(current);
++num_events_dispatched;
}
void EventMgr::Drain() void EventMgr::Drain()
{ {
if ( event_queue_flush_point ) if ( event_queue_flush_point )
@ -124,8 +104,34 @@ void EventMgr::Drain()
PLUGIN_HOOK_VOID(HOOK_DRAIN_EVENTS, HookDrainEvents()); PLUGIN_HOOK_VOID(HOOK_DRAIN_EVENTS, HookDrainEvents());
draining = true; draining = true;
while ( head )
Dispatch(); // Past Bro versions drained as long as there events, including when
// a handler queued new events during its execution. This could lead
// to endless loops in case a handler kept triggering its own event.
// We now limit this to just a couple of rounds. We do more than
// just one round to make it less likley to break existing scripts
// that expect the old behavior to trigger something quickly.
for ( int round = 0; head && round < 2; round++ )
{
Event* current = head;
head = 0;
tail = 0;
while ( current )
{
Event* next = current->NextEvent();
current_src = current->Source();
current_mgr = current->Mgr();
current_aid = current->Analyzer();
current->Dispatch();
Unref(current);
++num_events_dispatched;
current = next;
}
}
// Note: we might eventually need a general way to specify things to // Note: we might eventually need a general way to specify things to
// do after draining events. // do after draining events.

View file

@ -90,8 +90,6 @@ public:
delete_vals(vl); delete_vals(vl);
} }
void Dispatch();
void Dispatch(Event* event, bool no_remote = false) void Dispatch(Event* event, bool no_remote = false)
{ {
current_src = event->Source(); current_src = event->Source();

View file

@ -0,0 +1 @@
10

View file

@ -0,0 +1,31 @@
# @TEST-EXEC: bro %INPUT 2>&1 | grep -v termination | sort | uniq | wc -l >output
# @TEST-EXEC: btest-diff output
# In old version, the event would keep triggering endlessely, with the network
# time not moving forward and Bro not terminating.
#
# Note that the output will be 10 (not 20) because we still execute two rounds
# of events every time we drain.
redef exit_only_after_terminate=T;
global c = 0;
event test()
{
c += 1;
if ( c == 20 )
{
terminate();
return;
}
print network_time();
event test();
}
event bro_init()
{
event test();
}