diff options
| author | Rich Felker <dalias@aerifal.cx> | 2015-10-14 18:58:15 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2015-10-14 18:58:15 -0400 | 
| commit | 8d93cb57754f1f81f8e15bb74afd1725cead45c2 (patch) | |
| tree | b7a3a82bcdc031f34180c168726cd08e3ee7600b /src | |
| parent | 6fef8cafbd0f6f185897bc87feb1ff66e2e204e1 (diff) | |
| download | musl-8d93cb57754f1f81f8e15bb74afd1725cead45c2.tar.gz | |
fix strftime handling of out-of-range struct tm fields
strftime results are unspecified in this case, but should not invoke
undefined behaviour.
tm_wday, tm_yday, tm_mon and tm_year fields were used in signed int
arithmetic that could overflow.
based on patch by Szabolcs Nagy.
Diffstat (limited to 'src')
| -rw-r--r-- | src/time/strftime.c | 20 | 
1 files changed, 12 insertions, 8 deletions
| diff --git a/src/time/strftime.c b/src/time/strftime.c index e945bb7d..f1ccc4dd 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 ((tm->tm_wday + 371U - tm->tm_yday - 2) % 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 = (tm->tm_wday + 7U - tm->tm_yday - 1) % 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 = (tm->tm_wday + 371U - tm->tm_yday) % 7;  		if (jan1 != 4 && (jan1 != 3 || !is_leap(tm->tm_year)))  			val = 1;  	} @@ -52,21 +52,25 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  {  	nl_item item;  	long long val; -	const char *fmt; +	const char *fmt = "-";  	int width = 2;  	switch (f) {  	case 'a': +		if (tm->tm_wday > 6U) goto string;  		item = ABDAY_1 + tm->tm_wday;  		goto nl_strcat;  	case 'A': +		if (tm->tm_wday > 6U) goto string;  		item = DAY_1 + tm->tm_wday;  		goto nl_strcat;  	case 'h':  	case 'b': +		if (tm->tm_mon > 11U) goto string;  		item = ABMON_1 + tm->tm_mon;  		goto nl_strcat;  	case 'B': +		if (tm->tm_mon > 11U) goto string;  		item = MON_1 + tm->tm_mon;  		goto nl_strcat;  	case 'c': @@ -143,10 +147,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 +169,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; | 
