util.c: fix _WIN32 port of strptime (#3071)
In windows, time_t is a signed 32-bit integer type, so TIME_MAX needs to be declared as INT32_MAX instead of INT64_MAX. Also bump NetBSD's strptime to revision 1.65 from 1.63 to fix undefined behaviour (signed integer overflow) bugs. Related NetBSD problem report: https://gnats.netbsd.org/cgi-bin/query-pr-single.pl?number=58041 Noticed thanks to a compiler warning in the windows build CI. I declared the d variable as time_t instead of as unsigned to ensure that the signedness/size of TIME_MAX-d in the sse > TIME_MAX-d check is always correct, and to prevent -Wsign-compare warnings from triggering in the windows build.
This commit is contained in:
1 parent
1411ce63d5
commit
d777b6570c
1 file changed
+36
-29
+36
-29
@@ -818,40 +818,47 @@ recurse:
|
|||||||
LEGAL_ALT(ALT_O);
|
LEGAL_ALT(ALT_O);
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
#ifndef TIME_MAX
|
case 's': { /* seconds since the epoch */
|
||||||
#define TIME_MAX INT64_MAX
|
|
||||||
#endif
|
|
||||||
case 's': /* seconds since the epoch */
|
|
||||||
{
|
|
||||||
time_t sse = 0;
|
|
||||||
uint64_t rulim = TIME_MAX;
|
|
||||||
|
|
||||||
if (*bp < '0' || *bp > '9') {
|
|
||||||
bp = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
do {
|
|
||||||
sse *= 10;
|
|
||||||
sse += *bp++ - '0';
|
|
||||||
rulim /= 10;
|
|
||||||
} while ((sse * 10 <= TIME_MAX) &&
|
|
||||||
rulim && *bp >= '0' && *bp <= '9');
|
|
||||||
|
|
||||||
if (sse < 0 || (uint64_t)sse > TIME_MAX) {
|
|
||||||
bp = NULL;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (localtime_s(tm, &sse) == 0)
|
const time_t TIME_MAX = INT32_MAX;
|
||||||
#else
|
#else
|
||||||
if (localtime_r(&sse, tm))
|
const time_t TIME_MAX = INT64_MAX;
|
||||||
#endif
|
#endif
|
||||||
state |= S_YDAY | S_WDAY | S_MON | S_MDAY | S_YEAR;
|
time_t sse;
|
||||||
else
|
time_t d;
|
||||||
bp = NULL;
|
|
||||||
|
if (*bp < '0' || *bp > '9') {
|
||||||
|
bp = NULL;
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sse = *bp++ - '0';
|
||||||
|
while (*bp >= '0' && *bp <= '9') {
|
||||||
|
d = *bp++ - '0';
|
||||||
|
if (sse > TIME_MAX/10) {
|
||||||
|
bp = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sse *= 10;
|
||||||
|
if (sse > TIME_MAX - d) {
|
||||||
|
bp = NULL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
sse += d;
|
||||||
|
}
|
||||||
|
if (bp == NULL)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
if (localtime_s(tm, &sse))
|
||||||
|
#else
|
||||||
|
if (localtime_r(&sse, tm) == NULL)
|
||||||
|
#endif
|
||||||
|
bp = NULL;
|
||||||
|
else
|
||||||
|
state |= S_YDAY | S_WDAY | S_MON | S_MDAY | S_YEAR;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
case 'U': /* The week of year, beginning on sunday. */
|
case 'U': /* The week of year, beginning on sunday. */
|
||||||
case 'W': /* The week of year, beginning on monday. */
|
case 'W': /* The week of year, beginning on monday. */
|
||||||
|
|||||||
Reference in new issue
Block a user