[PATCH] Initialize sp->defaulttype in tzparse()
Hi, I found that sometimes the localtime() won't work properly, if sp->defaulttype is not set properly. For example, given the following code: time_t epoch = 0; setenv("TZ", "UTC+00", 1); tzset(); printf("%s", ctime(&epoch)); // (a) setenv("TZ", "Asia/Taipei", 1); tzset(); printf("%s", ctime(&epoch)); // (b) setenv("TZ", "UTC+00", 1); tzset(); printf("%s", ctime(&epoch)); // (c) The expected output should be: Thu Jan 1 00:00:00 1970 Thu Jan 1 08:00:00 1970 Thu Jan 1 00:00:00 1970 However, the output is: Thu Jan 1 00:00:00 1970 Thu Jan 1 08:00:00 1970 Thu Jan 1 08:00:00 1970 This is due to the fact that sp->defaulttype is set to 1 when we are using "Asia/Taipei" as the timezone, but it is not reset after we change the timezone to "UTC+00". As the result, the old value in sp->types[sp->defaulttype] is incorrectly used. The attached patch should resolve this issue. Please have a look. Thanks. Sincerely, Logan
Thanks, I pushed that into the experimental repository, albeit with a shorter commit log message. This prompted me to find a related bug when ALL_STATE is defined. I pushed this: From a4a5ceda025d03ff412ba3d551b9d511fb47e965 Mon Sep 17 00:00:00 2001 From: Paul Eggert <eggert@cs.ucla.edu> Date: Thu, 2 Jan 2014 13:16:39 -0800 Subject: [PATCH] Fix another 'localtime' initialization bug. * localtime.c (tzload) [ALL_STATE]: Initialize sp->goback and sp->goahead even if memory allocation fails. (tzload, tzsetwall, tzset, gmtsub) [ALL_STATE]: Use malloc, not calloc, since the !ALL_STATE code has to work with reused storage anyway. * NEWS: Document Logan Chien's fix. --- NEWS | 5 +++++ localtime.c | 18 ++++++++++-------- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/NEWS b/NEWS index 3d3a922..4d4f244 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,11 @@ News for the tz database Unreleased, experimental changes + Changes affecting code + + A uninitialized-storage bug in 'localtime' has been fixed. + (Thanks to Logan Chien.) + Changes affecting commentary The boundary of the US Pacific time zone is given more accurately. diff --git a/localtime.c b/localtime.c index 5ee2f3b..57d7d83 100644 --- a/localtime.c +++ b/localtime.c @@ -339,17 +339,19 @@ tzload(register const char *name, register struct state *const sp, 4 * TZ_MAX_TIMES]; } u_t; #ifdef ALL_STATE - register u_t * up; - - up = (u_t *) calloc(1, sizeof *up); - if (up == NULL) - return -1; + register u_t * const up = malloc(sizeof *up); #else /* !defined ALL_STATE */ u_t u; register u_t * const up = &u; #endif /* !defined ALL_STATE */ sp->goback = sp->goahead = FALSE; + +#ifdef ALL_STATE + if (up == NULL) + return -1; +#endif + if (name == NULL && (name = TZDEFAULT) == NULL) goto oops; { @@ -1190,7 +1192,7 @@ tzsetwall(void) #ifdef ALL_STATE if (lclptr == NULL) { - lclptr = calloc(1, sizeof *lclptr); + lclptr = malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; @@ -1221,7 +1223,7 @@ tzset(void) #ifdef ALL_STATE if (lclptr == NULL) { - lclptr = calloc(1, sizeof *lclptr); + lclptr = malloc(sizeof *lclptr); if (lclptr == NULL) { settzname(); /* all we can do */ return; @@ -1363,7 +1365,7 @@ gmtsub(const time_t *const timep, const int_fast32_t offset, if (!gmt_is_set) { gmt_is_set = TRUE; #ifdef ALL_STATE - gmtptr = calloc(1, sizeof *gmtptr); + gmtptr = malloc(sizeof *gmtptr); if (gmtptr != NULL) #endif /* defined ALL_STATE */ gmtload(gmtptr); -- 1.8.3.2
participants (2)
-
Logan Chien -
Paul Eggert