From 2c003df8864c3b30eb2e40056dbc88dd7f160a38 Mon Sep 17 00:00:00 2001 From: Todd White Date: Wed, 22 Jul 2026 12:04:12 -0400 Subject: [PATCH 1/2] CFRunLoop: do not wake a run loop the timer is not in CFRunLoopTimerSetNextFireDate always called CFRunLoopWakeUp on the timer run loop, which is NULL until the timer is added to one, so setting the fire date of a free-standing timer dereferenced NULL. Only wake a run loop the timer has been added to. --- Source/CFRunLoop.c | 8 ++++---- Tests/CFRunLoop/timer_setfiredate.m | 19 +++++++++++++++++++ 2 files changed, 23 insertions(+), 4 deletions(-) create mode 100644 Tests/CFRunLoop/timer_setfiredate.m diff --git a/Source/CFRunLoop.c b/Source/CFRunLoop.c index 88a4ad2..f148b0e 100644 --- a/Source/CFRunLoop.c +++ b/Source/CFRunLoop.c @@ -1845,8 +1845,8 @@ CFRunLoopTimerSetNextFireDate (CFRunLoopTimerRef timer, } timer->_nextFireDate = fireDate; - // Wake up the runloop so that it can recalculate the next timer date - // but since timers should be planned on current runloop only (NSTimer - // says so), this may not be necessary. - CFRunLoopWakeUp(timer->_runloop); + // Wake up the runloop so that it can recalculate the next timer date, + // but only if the timer has been added to one. + if (timer->_runloop != NULL) + CFRunLoopWakeUp(timer->_runloop); } diff --git a/Tests/CFRunLoop/timer_setfiredate.m b/Tests/CFRunLoop/timer_setfiredate.m new file mode 100644 index 0000000..ec85c56 --- /dev/null +++ b/Tests/CFRunLoop/timer_setfiredate.m @@ -0,0 +1,19 @@ +#include "CoreFoundation/CFRunLoop.h" +#include "../CFTesting.h" + +static void +fire (CFRunLoopTimerRef t, void *info) +{ +} + +int main (void) +{ + CFRunLoopTimerRef t = CFRunLoopTimerCreate (NULL, 100.0, 5.0, 0, 0, + fire, NULL); + + CFRunLoopTimerSetNextFireDate (t, 250.0); + PASS_CF (CFRunLoopTimerGetNextFireDate (t) == 250.0, + "Setting the fire date of a timer not in a run loop updates it."); + + return 0; +} From b473c71d3888e49117de5c03038a6f05dbe5fc82 Mon Sep 17 00:00:00 2001 From: Todd White Date: Thu, 23 Jul 2026 08:35:39 -0400 Subject: [PATCH 2/2] Tests: release the timer in the CFRunLoop fire-date test --- Tests/CFRunLoop/timer_setfiredate.m | 1 + 1 file changed, 1 insertion(+) diff --git a/Tests/CFRunLoop/timer_setfiredate.m b/Tests/CFRunLoop/timer_setfiredate.m index ec85c56..32d869d 100644 --- a/Tests/CFRunLoop/timer_setfiredate.m +++ b/Tests/CFRunLoop/timer_setfiredate.m @@ -15,5 +15,6 @@ int main (void) PASS_CF (CFRunLoopTimerGetNextFireDate (t) == 250.0, "Setting the fire date of a timer not in a run loop updates it."); + CFRelease (t); return 0; }