From 6d0edf9d07379082d9a2c66c71e929ad510b29d2 Mon Sep 17 00:00:00 2001 From: Peter Hutterer Date: Mon, 17 Jul 2017 12:30:25 +1000 Subject: [PATCH] timer: always restart the timer loop when we called one of them If a timer_func causes the removal or addition of a different timer, our tmp pointer from the list_for_each_safe may not be valid anymore. This was triggered by having the debounce code trigger a middle button state change, which caused that timer to be cancelled. Signed-off-by: Peter Hutterer --- src/timer.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/timer.c b/src/timer.c index 5d9fc512..a136b8d5 100644 --- a/src/timer.c +++ b/src/timer.c @@ -128,7 +128,7 @@ static void libinput_timer_handler(void *data) { struct libinput *libinput = data; - struct libinput_timer *timer, *tmp; + struct libinput_timer *timer; uint64_t now; uint64_t discard; int r; @@ -144,7 +144,8 @@ libinput_timer_handler(void *data) if (now == 0) return; - list_for_each_safe(timer, tmp, &libinput->timer.list, link) { +restart: + list_for_each(timer, &libinput->timer.list, link) { if (timer->expire == 0) continue; @@ -153,6 +154,16 @@ libinput_timer_handler(void *data) as timer_func may re-arm it */ libinput_timer_cancel(timer); timer->timer_func(now, timer->timer_func_data); + + /* + * Restart the loop. We can't use + * list_for_each_safe() here because that only + * allows removing one (our) timer per timer_func. + * But the timer func may trigger another unrelated + * timer to be cancelled and removed, causing a + * segfault. + */ + goto restart; } } }