>From e8891b06e0c698c0334f08e996f3b0d733f8ede7 Mon Sep 17 00:00:00 2001 From: Szabolcs Nagy Date: Sun, 20 Sep 2015 19:41:23 +0000 Subject: [PATCH] fix strftime to handle out of range tm fields without UB strftime returns unspecifed result with out of range tm fields, but it should not invoke undefined behaviour. tm_wday, tm_yday, tm_mon and tm_year fields were used in signed int arithmetics that could overflow. --- src/time/strftime.c | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/time/strftime.c b/src/time/strftime.c index e945bb7..a1db37c 100644 --- a/src/time/strftime.c +++ b/src/time/strftime.c @@ -21,24 +21,24 @@ static int is_leap(int y) static int week_num(const struct tm *tm) { - int val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7; + int val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; /* If 1 Jan is just 1-3 days past Monday, * the previous week is also in this year. */ - if ((tm->tm_wday - tm->tm_yday - 2 + 371) % 7 <= 2) + if ((0U + tm->tm_wday - tm->tm_yday - 2 + 371) % 7 <= 2) val++; if (!val) { val = 52; /* If 31 December of prev year a Thursday, * or Friday of a leap year, then the * prev year has 53 weeks. */ - int dec31 = (tm->tm_wday - tm->tm_yday - 1 + 7) % 7; + int dec31 = (0U + tm->tm_wday - tm->tm_yday - 1 + 7) % 7; if (dec31 == 4 || (dec31 == 5 && is_leap(tm->tm_year%400-1))) val++; } else if (val == 53) { /* If 1 January is not a Thursday, and not * a Wednesday of a leap year, then this * year has only 52 weeks. */ - int jan1 = (tm->tm_wday - tm->tm_yday + 371) % 7; + int jan1 = (0U + tm->tm_wday - tm->tm_yday + 371) % 7; if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year))) val = 1; } @@ -57,17 +57,17 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * switch (f) { case 'a': - item = ABDAY_1 + tm->tm_wday; + item = ABDAY_1 + tm->tm_wday%7U; goto nl_strcat; case 'A': - item = DAY_1 + tm->tm_wday; + item = DAY_1 + tm->tm_wday%7U; goto nl_strcat; case 'h': case 'b': - item = ABMON_1 + tm->tm_mon; + item = ABMON_1 + tm->tm_mon%12U; goto nl_strcat; case 'B': - item = MON_1 + tm->tm_mon; + item = MON_1 + tm->tm_mon%12U; goto nl_strcat; case 'c': item = D_T_FMT; @@ -143,10 +143,10 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * width = 1; goto number; case 'U': - val = (tm->tm_yday + 7 - tm->tm_wday) / 7; + val = (tm->tm_yday + 7U - tm->tm_wday) / 7; goto number; case 'W': - val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7; + val = (tm->tm_yday + 7U - (tm->tm_wday+6U)%7) / 7; goto number; case 'V': val = week_num(tm); @@ -165,7 +165,7 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm * val = tm->tm_year % 100; goto number; case 'Y': - val = tm->tm_year + 1900; + val = tm->tm_year + 1900LL; if (val >= 10000) { *l = snprintf(*s, sizeof *s, "+%lld", val); return *s; -- 2.4.1