From 1e582ede3b04d12aae11fc5378a446a392054f1c Mon Sep 17 00:00:00 2001 From: Gibeom Gwon Date: Sun, 6 Mar 2022 09:45:38 +0900 Subject: [PATCH] calendarspec: fix possibly skips next elapse If the time unit changes after adding the repetition value, the timer may skip the next elapse. This patch reset sub time units to minimum value when upper unit is changed. Fixes #22665. --- src/shared/calendarspec.c | 27 ++++++++++++++++++++------- src/test/test-calendarspec.c | 2 ++ 2 files changed, 22 insertions(+), 7 deletions(-) diff --git a/src/shared/calendarspec.c b/src/shared/calendarspec.c index 71256de8e14..79fd1359b66 100644 --- a/src/shared/calendarspec.c +++ b/src/shared/calendarspec.c @@ -1181,6 +1181,7 @@ static int find_matching_component( static int tm_within_bounds(struct tm *tm, bool utc) { struct tm t; + int cmp; assert(tm); /* @@ -1195,13 +1196,25 @@ static int tm_within_bounds(struct tm *tm, bool utc) { if (mktime_or_timegm(&t, utc) < 0) return negative_errno(); - /* Did any normalization take place? If so, it was out of bounds before */ - int cmp = CMP(t.tm_year, tm->tm_year) ?: - CMP(t.tm_mon, tm->tm_mon) ?: - CMP(t.tm_mday, tm->tm_mday) ?: - CMP(t.tm_hour, tm->tm_hour) ?: - CMP(t.tm_min, tm->tm_min) ?: - CMP(t.tm_sec, tm->tm_sec); + /* + * Did any normalization take place? If so, it was out of bounds before. + * Normalization could skip next elapse, e.g. result of normalizing 3-33 + * is 4-2. This skips 4-1. So reset the sub time unit if upper unit was + * out of bounds. Normalization has occurred implies find_matching_component() > 0, + * other sub time units are already reset in find_next(). + */ + if ((cmp = CMP(t.tm_year, tm->tm_year)) != 0) + t.tm_mon = 0; + else if ((cmp = CMP(t.tm_mon, tm->tm_mon)) != 0) + t.tm_mday = 1; + else if ((cmp = CMP(t.tm_mday, tm->tm_mday)) != 0) + t.tm_hour = 0; + else if ((cmp = CMP(t.tm_hour, tm->tm_hour)) != 0) + t.tm_min = 0; + else if ((cmp = CMP(t.tm_min, tm->tm_min)) != 0) + t.tm_sec = 0; + else + cmp = CMP(t.tm_sec, tm->tm_sec); if (cmp < 0) return -EDEADLK; /* Refuse to go backward */ diff --git a/src/test/test-calendarspec.c b/src/test/test-calendarspec.c index e1862f4eb88..71814e3115b 100644 --- a/src/test/test-calendarspec.c +++ b/src/test/test-calendarspec.c @@ -199,6 +199,8 @@ TEST(calendar_spec_next) { test_next("2016-02~01 UTC", "", 12345, 1456704000000000); test_next("Mon 2017-05~01..07 UTC", "", 12345, 1496016000000000); test_next("Mon 2017-05~07/1 UTC", "", 12345, 1496016000000000); + test_next("*-*-01/5 04:00:00 UTC", "", 1646010000000000, 1646107200000000); + test_next("*-01/7-01 04:00:00 UTC", "", 1664607600000000, 1672545600000000); test_next("2017-08-06 9,11,13,15,17:00 UTC", "", 1502029800000000, 1502031600000000); test_next("2017-08-06 9..17/2:00 UTC", "", 1502029800000000, 1502031600000000); test_next("2016-12-* 3..21/6:00 UTC", "", 1482613200000001, 1482634800000000);