>Synopsis: strptime segfaults if anything follows %Z in template
>Category: library
>Environment:
System : OpenBSD 5.5
Details : OpenBSD 5.5 (GENERIC.MP) #0: Mon May 5 18:58:07 UTC 2014
[email protected]:/usr/src/sys/arch/amd64/compile/GENERIC.MP
Architecture: OpenBSD.amd64
Machine : amd64
>Description:
valen% ./s
GMT ok
US/Pacific PST ok
[1] 1289 segmentation fault (core dumped) ./s
>How-To-Repeat:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
struct tm ilikebigsegfaults;
char *where;
setenv("TZ", "GMT", 1);
where = strptime("GMT anything ok", "%Z anything ", &ilikebigsegfaults);
if (where != NULL)
fprintf(stderr, "GMT %s\n", where);
else
fprintf(stderr, "GMT not ok - NULL\n");
setenv("TZ", "US/Pacific", 1);
where = strptime("PST anything ok", "%Z anything ", &ilikebigsegfaults);
if (where != NULL)
fprintf(stderr, "US/Pacific PST %s\n", where);
else
fprintf(stderr, "US/Pacific PST not ok - NULL\n");
where = strptime("UTC anything", "%Z anything", &ilikebigsegfaults);
if (where == NULL)
fprintf(stderr, "US/Pacific UTC ok - no match\n");
setenv("TZ", "UTC", 1);
where = strptime("UTC anything ok", "%Z anything ", &ilikebigsegfaults);
if (where != NULL)
fprintf(stderr, "UTC %s\n", where);
else
fprintf(stderr, "UTC not ok - NULL\n");
where = strptime("not ok", "%Z", &ilikebigsegfaults);
if (where == NULL)
fprintf(stderr, "UTC neg ok\n");
else
fprintf(stderr, "UTC neg %s - should fail\n", where);
exit(0);
}
>Fix:
Though there might be better ways, e.g. to make tzname contain the needful,
given that there might be other ways of naming UTC?
--- /usr/src/lib/libc/time/strptime.c.orig Tue Jul 8 05:16:27 2014
+++ /usr/src/lib/libc/time/strptime.c Tue Jul 8 05:32:23 2014
@@ -56,9 +56,8 @@
#define FIELD_TM_YEAR (1 << 4)
static char gmt[] = { "GMT" };
-#ifdef TM_ZONE
static char utc[] = { "UTC" };
-#endif
+
/* RFC-822/RFC-2822 */
static const char * const nast[5] = {
"EST", "CST", "MST", "PST", "\0\0\0"
@@ -409,6 +408,15 @@
tm->TM_ZONE = gmt;
#endif
bp += 3;
+ } else if (strncmp((const char *)bp, utc, 3) == 0) {
+ tm->tm_isdst = 0;
+#ifdef TM_GMTOFF
+ tm->TM_GMTOFF = 0;
+#endif
+#ifdef TM_ZONE
+ tm->TM_ZONE = utc;
+#endif
+ bp += 3;
} else {
ep = _find_string(bp, &i,
(const char * const *)tzname,
@@ -421,8 +429,10 @@
#ifdef TM_ZONE
tm->TM_ZONE = tzname[i];
#endif
+ bp = ep;
+ } else {
+ return NULL;
}
- bp = ep;
}
continue;