Fix BZ #18985 -- out of range data to strftime() causes a segfault

This commit is contained in:
Paul Pluzhnikov 2015-09-26 13:27:48 -07:00
parent fa752c6981
commit d36c75fc0d
4 changed files with 73 additions and 9 deletions

View File

@ -1,3 +1,11 @@
2015-09-26 Paul Pluzhnikov <ppluzhnikov@google.com>
[BZ #18985]
* time/strftime_l.c (a_wkday, f_wkday, a_month, f_month): Range check.
(__strftime_internal): Likewise.
* time/tst-strftime.c (do_bz18985): New test.
(do_test): Call it.
2015-09-26 Joseph Myers <joseph@codesourcery.com>
[BZ #18956]

2
NEWS
View File

@ -16,7 +16,7 @@ Version 2.23
18618, 18647, 18661, 18674, 18675, 18681, 18757, 18778, 18781, 18787,
18789, 18790, 18795, 18796, 18803, 18820, 18823, 18824, 18825, 18857,
18863, 18870, 18872, 18873, 18875, 18887, 18921, 18951, 18952, 18956,
18961, 18966, 18967, 18970, 18977, 18980, 18981, 19003.
18961, 18966, 18967, 18970, 18977, 18980, 18981, 18985, 19003.
* The obsolete header <regexp.h> has been removed. Programs that require
this header must be updated to use <regex.h> instead.

View File

@ -510,13 +510,17 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
only a few elements. Dereference the pointers only if the format
requires this. Then it is ok to fail if the pointers are invalid. */
# define a_wkday \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday))
((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
? "?" : _NL_CURRENT (LC_TIME, NLW(ABDAY_1) + tp->tm_wday)))
# define f_wkday \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday))
((const CHAR_T *) (tp->tm_wday < 0 || tp->tm_wday > 6 \
? "?" : _NL_CURRENT (LC_TIME, NLW(DAY_1) + tp->tm_wday)))
# define a_month \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon))
((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
? "?" : _NL_CURRENT (LC_TIME, NLW(ABMON_1) + tp->tm_mon)))
# define f_month \
((const CHAR_T *) _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon))
((const CHAR_T *) (tp->tm_mon < 0 || tp->tm_mon > 11 \
? "?" : _NL_CURRENT (LC_TIME, NLW(MON_1) + tp->tm_mon)))
# define ampm \
((const CHAR_T *) _NL_CURRENT (LC_TIME, tp->tm_hour > 11 \
? NLW(PM_STR) : NLW(AM_STR)))
@ -526,8 +530,10 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
# define ap_len STRLEN (ampm)
#else
# if !HAVE_STRFTIME
# define f_wkday (weekday_name[tp->tm_wday])
# define f_month (month_name[tp->tm_mon])
# define f_wkday (tp->tm_wday < 0 || tp->tm_wday > 6 \
? "?" : weekday_name[tp->tm_wday])
# define f_month (tp->tm_mon < 0 || tp->tm_mon > 11 \
? "?" : month_name[tp->tm_mon])
# define a_wkday f_wkday
# define a_month f_month
# define ampm (L_("AMPM") + 2 * (tp->tm_hour > 11))
@ -1321,7 +1327,7 @@ __strftime_internal (s, maxsize, format, tp, tzset_called ut_argument
*tzset_called = true;
}
# endif
zone = tzname[tp->tm_isdst];
zone = tp->tm_isdst <= 1 ? tzname[tp->tm_isdst] : "?";
}
#endif
if (! zone)

View File

@ -4,6 +4,56 @@
#include <time.h>
static int
do_bz18985 (void)
{
char buf[1000];
struct tm ttm;
int rc, ret = 0;
memset (&ttm, 1, sizeof (ttm));
ttm.tm_zone = NULL; /* Dereferenced directly if non-NULL. */
rc = strftime (buf, sizeof (buf), "%a %A %b %B %c %z %Z", &ttm);
if (rc == 66)
{
const char expected[]
= "? ? ? ? ? ? 16843009 16843009:16843009:16843009 16844909 +467836 ?";
if (0 != strcmp (buf, expected))
{
printf ("expected:\n %s\ngot:\n %s\n", expected, buf);
ret += 1;
}
}
else
{
printf ("expected 66, got %d\n", rc);
ret += 1;
}
/* Check negative values as well. */
memset (&ttm, 0xFF, sizeof (ttm));
ttm.tm_zone = NULL; /* Dereferenced directly if non-NULL. */
rc = strftime (buf, sizeof (buf), "%a %A %b %B %c %z %Z", &ttm);
if (rc == 30)
{
const char expected[] = "? ? ? ? ? ? -1 -1:-1:-1 1899 ";
if (0 != strcmp (buf, expected))
{
printf ("expected:\n %s\ngot:\n %s\n", expected, buf);
ret += 1;
}
}
else
{
printf ("expected 30, got %d\n", rc);
ret += 1;
}
return ret;
}
static struct
{
const char *fmt;
@ -104,7 +154,7 @@ do_test (void)
}
}
return result;
return result + do_bz18985 ();
}
#define TEST_FUNCTION do_test ()