From c79f5d741e19f8e30450e6064ed30b5d6ac19175 Mon Sep 17 00:00:00 2001 From: James Hunt Date: Tue, 17 Apr 2012 17:37:04 +0100 Subject: [PATCH] Reference event sources signalled by epoll before timeout handling. If ply_event_loop_handle_timeouts() is called before the events returned by epoll_wait() are referenced, a timeout handler can free an event source leading to undefined behaviour (and frequently SIGSEGV crashes) once ply_event_loop_handle_timeouts() has finished since ply_event_loop_process_pending_events() continues to try and process the now invalid event sources. Thanks to cjwatson for a simpler solution to my original fix. Save errno values to ensure logic is robust in case handler makes system call. Signed-off-by: James Hunt --- src/libply/ply-event-loop.c | 29 ++++++++++++++++------------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/src/libply/ply-event-loop.c b/src/libply/ply-event-loop.c index acfdc5d..a1abdb6 100644 --- a/src/libply/ply-event-loop.c +++ b/src/libply/ply-event-loop.c @@ -1255,6 +1255,7 @@ void ply_event_loop_process_pending_events (ply_event_loop_t *loop) { int number_of_received_events, i; + int saved_errno; static struct epoll_event events[PLY_EVENT_LOOP_NUM_EVENT_HANDLERS]; assert (loop != NULL); @@ -1277,30 +1278,32 @@ ply_event_loop_process_pending_events (ply_event_loop_t *loop) number_of_received_events = epoll_wait (loop->epoll_fd, events, PLY_EVENT_LOOP_NUM_EVENT_HANDLERS, timeout); - - ply_event_loop_handle_timeouts (loop); + saved_errno = errno; if (number_of_received_events < 0) { - if (errno != EINTR && errno != EAGAIN) + if (saved_errno != EINTR && saved_errno != EAGAIN) { ply_event_loop_exit (loop, 255); return; } } - } - while ((number_of_received_events < 0) && ((errno == EINTR) || (errno == EAGAIN))); - /* first reference all sources, so they stay alive for the duration of this - * iteration of the loop - */ - for (i = 0; i < number_of_received_events; i++) - { - ply_event_source_t *source; - source = (ply_event_source_t *) (events[i].data.ptr); + /* Reference all sources, so they stay alive for the duration of this + * iteration of the loop + */ + for (i = 0; i < number_of_received_events; i++) + { + ply_event_source_t *source; + source = (ply_event_source_t *) (events[i].data.ptr); + + ply_event_source_take_reference (source); + } + + ply_event_loop_handle_timeouts (loop); - ply_event_source_take_reference (source); } + while ((number_of_received_events < 0) && ((saved_errno == EINTR) || (saved_errno == EAGAIN))); /* Then process the incoming events */ -- 1.7.9.5