From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/8532 Path: news.gmane.org!not-for-mail From: Szabolcs Nagy Newsgroups: gmane.linux.lib.musl.general Subject: Re: out of range struct tm fields in strftime Date: Sun, 20 Sep 2015 21:54:50 +0200 Message-ID: <20150920195450.GD10551@port70.net> References: <20150920124450.GA10551@port70.net> <20150920163629.GL17773@brightrain.aerifal.cx> <20150920164435.GB10551@port70.net> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: plane.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="MfFXiAuoTsnnDAfZ" X-Trace: ger.gmane.org 1442778905 15567 80.91.229.3 (20 Sep 2015 19:55:05 GMT) X-Complaints-To: usenet@ger.gmane.org NNTP-Posting-Date: Sun, 20 Sep 2015 19:55:05 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-8544-gllmg-musl=m.gmane.org@lists.openwall.com Sun Sep 20 21:55:05 2015 Return-path: Envelope-to: gllmg-musl@m.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by plane.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1ZdkhU-0001lW-Kj for gllmg-musl@m.gmane.org; Sun, 20 Sep 2015 21:55:04 +0200 Original-Received: (qmail 11297 invoked by uid 550); 20 Sep 2015 19:55:02 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 11266 invoked from network); 20 Sep 2015 19:55:02 -0000 Mail-Followup-To: musl@lists.openwall.com Content-Disposition: inline In-Reply-To: <20150920164435.GB10551@port70.net> User-Agent: Mutt/1.5.23 (2014-03-12) Xref: news.gmane.org gmane.linux.lib.musl.general:8532 Archived-At: --MfFXiAuoTsnnDAfZ Content-Type: text/plain; charset=us-ascii Content-Disposition: inline * Szabolcs Nagy [2015-09-20 18:44:35 +0200]: > * Rich Felker [2015-09-20 12:36:29 -0400]: > > On Sun, Sep 20, 2015 at 02:44:50PM +0200, Szabolcs Nagy wrote: > > > out of range tm fields should not be treated as ub > > > as noted in the thread > > > http://sourceware.org/ml/libc-alpha/2015-09/msg00546.html > > > > > > i have a patch but there might be simpler approaches > > > > Wouldn't it be less invasive to just make some small changes like > > putting a U on some of the constants so that the arithmetic happens as > > unsigned? > > > > that might be simpler (and probably generates better > code for div,mod by const) > > but for the nl_langinfo item computation the range > has to be limited properly (tm_wday and tm_mon are > affected). implemented this approach with wday%7U and using some 0U+ --MfFXiAuoTsnnDAfZ Content-Type: text/x-diff; charset=us-ascii Content-Disposition: attachment; filename="0001-fix-strftime-to-handle-out-of-range-tm-fields-withou.patch" >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 --MfFXiAuoTsnnDAfZ--