From a6e075a2c40be1745f1ae0b9ba210ce06438179d Mon Sep 17 00:00:00 2001 From: yuripv Date: Wed, 17 Oct 2018 14:51:43 +0000 Subject: [PATCH] strptime: fix parsing of tm_year when both %C and %y appear in the format string in arbitrary order. This makes the related test cases in lib/libc/tests/time (not yet connected to the build) pass. While here, don't error on negative tm_year value based on the APPLICATION USAGE in http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/time.h.html (glibc does the same): tm_year is a signed value; therefore, years before 1900 may be represented. Approved by: re (gjb), kib (mentor) Differential Revision: https://reviews.freebsd.org/D17550 --- lib/libc/stdtime/strptime.c | 26 +++++++++++++++++--------- 1 file changed, 17 insertions(+), 9 deletions(-) diff --git a/lib/libc/stdtime/strptime.c b/lib/libc/stdtime/strptime.c index 78cef6bf839e..e011a7fe8dc8 100644 --- a/lib/libc/stdtime/strptime.c +++ b/lib/libc/stdtime/strptime.c @@ -95,6 +95,7 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, int i, len; int flags; int Ealternative, Oalternative; + int century, year; const struct lc_time_T *tptr = __get_current_time_locale(locale); static int start_of_month[2][13] = { {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365}, @@ -102,6 +103,8 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, }; flags = FLAG_NONE; + century = -1; + year = -1; ptr = fmt; while (*ptr != 0) { @@ -146,10 +149,8 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, i += *buf - '0'; len--; } - if (i < 19) - return (NULL); - tm->tm_year = i * 100 - TM_YEAR_BASE; + century = i; flags |= FLAG_YEAR; break; @@ -527,13 +528,9 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, len--; } if (c == 'Y') - i -= TM_YEAR_BASE; - if (c == 'y' && i < 69) - i += 100; - if (i < 0) - return (NULL); + century = i / 100; + year = i % 100; - tm->tm_year = i; flags |= FLAG_YEAR; break; @@ -611,6 +608,17 @@ _strptime(const char *buf, const char *fmt, struct tm *tm, int *GMTp, } } + if (century != -1 || year != -1) { + if (year == -1) + year = 0; + if (century == -1) { + if (year < 69) + year += 100; + } else + year += century * 100 - TM_YEAR_BASE; + tm->tm_year = year; + } + if (!(flags & FLAG_YDAY) && (flags & FLAG_YEAR)) { if ((flags & (FLAG_MONTH | FLAG_MDAY)) == (FLAG_MONTH | FLAG_MDAY)) {