From: Guus Sliepen Date: Tue, 28 Apr 2020 21:19:29 +0000 (+0200) Subject: Avoid a segfault when setting a timeout to 0. X-Git-Url: https://git.meshlink.io/?a=commitdiff_plain;h=89ef35a422dc1c1ddaf583a3ee2a07881e1acc11;p=meshlink Avoid a segfault when setting a timeout to 0. The event loop was assuming that a timespec value of {0, 0} meant that the timer was not added to the timer tree. However, it was possible for other parts of the code to set the value to {0, 0}, which could result in a segmentation fault. Use the splay_node_t data pointer to check whether a timeout is linked into the tree instead. --- diff --git a/src/event.c b/src/event.c index 739ff35d..40dbd18e 100644 --- a/src/event.c +++ b/src/event.c @@ -64,10 +64,6 @@ static void timespec_clear(struct timespec *a) { a->tv_sec = 0; } -static bool timespec_isset(const struct timespec *a) { - return a->tv_sec; -} - static int io_compare(const io_t *a, const io_t *b) { return a->fd - b->fd; } @@ -137,7 +133,6 @@ void io_del(event_loop_t *loop, io_t *io) { void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void *data, struct timespec *tv) { timeout->cb = cb; timeout->data = data; - timeout->node.data = timeout; timeout_set(loop, timeout, tv); } @@ -145,8 +140,10 @@ void timeout_add(event_loop_t *loop, timeout_t *timeout, timeout_cb_t cb, void * void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timespec *tv) { assert(timeout->cb); - if(timespec_isset(&timeout->tv)) { + if(timeout->node.data) { splay_unlink_node(&loop->timeouts, &timeout->node); + } else { + timeout->node.data = timeout; } if(!loop->now.tv_sec) { @@ -163,7 +160,11 @@ void timeout_set(event_loop_t *loop, timeout_t *timeout, struct timespec *tv) { } static void timeout_disable(event_loop_t *loop, timeout_t *timeout) { - splay_unlink_node(&loop->timeouts, &timeout->node); + if(timeout->node.data) { + splay_unlink_node(&loop->timeouts, &timeout->node); + timeout->node.data = NULL; + } + timespec_clear(&timeout->tv); } @@ -172,7 +173,7 @@ void timeout_del(event_loop_t *loop, timeout_t *timeout) { return; } - if(timespec_isset(&timeout->tv)) { + if(timeout->node.data) { timeout_disable(loop, timeout); }