diff options
| author | Rich Felker <dalias@aerifal.cx> | 2013-08-22 19:44:02 -0400 | 
|---|---|---|
| committer | Rich Felker <dalias@aerifal.cx> | 2013-08-22 19:44:02 -0400 | 
| commit | 33413cdd25c58f0e57061e0a3cb7a29d492ba785 (patch) | |
| tree | 0d88bf261c7088e49c9c593e00620434f523fafc /src | |
| parent | 87e133b352c419383116a05cbe251dc396de062f (diff) | |
| download | musl-33413cdd25c58f0e57061e0a3cb7a29d492ba785.tar.gz | |
simplify strftime and fix integer overflows
use a long long value so that even with offsets, values cannot
overflow. instead of using different format strings for different
numeric formats, simply use a per-format width and %0*lld for all of
them.
this width specifier is not for use with strftime field widths; that
will be a separate step in the caller.
Diffstat (limited to 'src')
| -rw-r--r-- | src/time/strftime.c | 40 | 
1 files changed, 12 insertions, 28 deletions
diff --git a/src/time/strftime.c b/src/time/strftime.c index 880e41a1..19ffdbca 100644 --- a/src/time/strftime.c +++ b/src/time/strftime.c @@ -6,8 +6,6 @@  #include <limits.h>  #include "libc.h" -// FIXME: integer overflows -  const char *__nl_langinfo_l(nl_item, locale_t);  static int is_leap(int y) @@ -49,8 +47,9 @@ size_t __strftime_l(char *restrict, size_t, const char *restrict, const struct t  const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *tm, locale_t loc)  {  	nl_item item; -	int val; +	long long val;  	const char *fmt; +	int width = 2;  	switch (f) {  	case 'a': @@ -70,55 +69,45 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  		item = D_T_FMT;  		goto nl_strftime;  	case 'C': -		val = (1900+tm->tm_year) / 100; -		fmt = "%02d"; +		val = (1900LL+tm->tm_year) / 100;  		goto number;  	case 'd':  		val = tm->tm_mday; -		fmt = "%02d";  		goto number;  	case 'D':  		fmt = "%m/%d/%y";  		goto recu_strftime;  	case 'e':  		val = tm->tm_mday; -		fmt = "%2d";  		goto number;  	case 'F':  		fmt = "%Y-%m-%d";  		goto recu_strftime;  	case 'g':  	case 'G': -		fmt = "%04d"; -		val = tm->tm_year + 1900; +		val = tm->tm_year + 1900LL;  		if (tm->tm_yday < 3 && week_num(tm) != 1) val--;  		else if (tm->tm_yday > 360 && week_num(tm) == 1) val++; -		if (f=='g') { -			fmt = "%02d"; -			val %= 100; -		} +		if (f=='g') val %= 100; +		else width = 4;  		goto number;  	case 'H':  		val = tm->tm_hour; -		fmt = "%02d";  		goto number;  	case 'I':  		val = tm->tm_hour;  		if (!val) val = 12;  		else if (val > 12) val -= 12; -		fmt = "%02d";  		goto number;  	case 'j':  		val = tm->tm_yday+1; -		fmt = "%03d"; +		width = 3;  		goto number;  	case 'm':  		val = tm->tm_mon+1; -		fmt = "%02d";  		goto number;  	case 'M':  		val = tm->tm_min; -		fmt = "%02d";  		goto number;  	case 'n':  		*l = 1; @@ -134,7 +123,6 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  		goto recu_strftime;  	case 'S':  		val = tm->tm_sec; -		fmt = "%02d";  		goto number;  	case 't':  		*l = 1; @@ -144,23 +132,20 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  		goto recu_strftime;  	case 'u':  		val = tm->tm_wday ? tm->tm_wday : 7; -		fmt = "%d"; +		width = 1;  		goto number;  	case 'U':  		val = (tm->tm_yday + 7 - tm->tm_wday) / 7; -		fmt = "%02d";  		goto number;  	case 'W':  		val = (tm->tm_yday + 7 - (tm->tm_wday+6)%7) / 7; -		fmt = "%02d";  		goto number;  	case 'V':  		val = week_num(tm); -		fmt = "%02d";  		goto number;  	case 'w':  		val = tm->tm_wday; -		fmt = "%d"; +		width = 1;  		goto number;  	case 'x':  		item = D_FMT; @@ -170,11 +155,10 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  		goto nl_strftime;  	case 'y':  		val = tm->tm_year % 100; -		fmt = "%02d";  		goto number;  	case 'Y': -		val = tm->tm_year + 1900; -		fmt = "%04d"; +		val = tm->tm_year + 1900LL; +		width = 4;  		goto number;  	case 'z':  		val = -tm->__tm_gmtoff; @@ -190,7 +174,7 @@ const char *__strftime_fmt_1(char (*s)[100], size_t *l, int f, const struct tm *  		return 0;  	}  number: -	*l = snprintf(*s, sizeof *s, fmt, val); +	*l = snprintf(*s, sizeof *s, "%0*lld", width, val);  	return *s;  nl_strcat:  	fmt = __nl_langinfo_l(item, loc);  | 
