From 8994c3638458f3ca04e10667241281ae5b667d0b Mon Sep 17 00:00:00 2001 From: Dirk Feytons Date: Wed, 18 Jun 2025 23:42:02 +0200 Subject: [PATCH] uloop: fix removing interval timer that fired at that time Previously the following scenario was possible: 1. event loop returns with some events 2. one event triggers a callback invocation that removes a timer, possibly as part of a bigger cleanup 3. another event is that same timer firing, which invokes the timer's callback, which in turn potentially accesses data that no longer exists due to the earlier cleanup Fix this by using uloop_fd_delete() instead of __uloop_fd_delete() when removing the interval timer so a possible pending event is cleared. The above fix breaks the feature that uloop_interval_cancel() can be called again on an already cancelled interval timer: 1. The first cancel closes the timerfd and memsets the whole uloop_fd struct to 0. 2. In every subsequent cancel the uloop_fd_delete() call will return 0 which results in the following code closing fd 0 due to the memset. Avoid this by checking the struct uloop_fd registered flag as first thing in the timer_remove() function. Signed-off-by: Dirk Feytons --- uloop-epoll.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/uloop-epoll.c b/uloop-epoll.c index d7b3acf..6513a75 100644 --- a/uloop-epoll.c +++ b/uloop-epoll.c @@ -162,7 +162,10 @@ static int timer_register(struct uloop_interval *tm, unsigned int msecs) static int timer_remove(struct uloop_interval *tm) { - int ret = __uloop_fd_delete(&tm->priv.ufd); + if (!tm->priv.ufd.registered) + return 0; + + int ret = uloop_fd_delete(&tm->priv.ufd); if (ret == 0) { close(tm->priv.ufd.fd);