This avoids a call to malloc in some failure cases (e.g., bad
TZ setting) and should simplify future improvements.
* localtime.c (ALL_STATE): Default to 0.  All uses changed.
(tzloadbody): Last arg is now pointer-to-pointer, instead of just
pointer, so that in the ALL_STATE case we malloc the storage
instead of the caller doing it.  Caller changed.
---
 localtime.c | 53 ++++++++++++++++++++++++++++++++++-------------------
 1 file changed, 34 insertions(+), 19 deletions(-)

diff --git a/localtime.c b/localtime.c
index ef094560..c7b9f663 100644
--- a/localtime.c
+++ b/localtime.c
@@ -378,12 +378,14 @@ static struct tm *timesub(time_t const *, int_fast32_t, 
struct state const *,
                          struct tm *);
 static bool tzparse(char const *, struct state *, struct state const *);
 
-#ifdef ALL_STATE
+#ifndef ALL_STATE
+# define ALL_STATE 0
+#endif
+
+#if ALL_STATE
 static struct state *  lclptr;
 static struct state *  gmtptr;
-#endif /* defined ALL_STATE */
-
-#ifndef ALL_STATE
+#else
 static struct state    lclmem;
 static struct state    gmtmem;
 static struct state *const lclptr = &lclmem;
@@ -702,18 +704,19 @@ enum { TZLOAD_TZSTRING = 2 }; /* Read any 
newline-surrounded TZ string.  */
 enum { TZLOAD_TZDIR_SUB = 4 }; /* TZ should be a file under TZDIR.  */
 
 /* Load tz data from the file named NAME into *SP.  Respect TZLOADFLAGS.
-   Use *LSP for temporary storage.  Return 0 on
+   Use **LSPP for temporary storage.  Return 0 on
    success, an errno value on failure.  */
 static int
 tzloadbody(char const *name, struct state *sp, char tzloadflags,
-          union local_storage *lsp)
+          union local_storage **lspp)
 {
        register int                    i;
        register int                    fid;
        register int                    stored;
        register ssize_t                nread;
        char const *relname;
-       register union input_buffer *up = &lsp->u.u;
+       union local_storage *lsp = *lspp;
+       union input_buffer *up;
        register int tzheadsize = sizeof(struct tzhead);
        int dd = AT_FDCWD;
        int oflags = (O_RDONLY | O_BINARY | O_CLOEXEC | O_CLOFORK
@@ -793,6 +796,12 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
                /* Create a string "TZDIR/NAME".  Using sprintf here
                   would pull in stdio (and would fail if the
                   resulting string length exceeded INT_MAX!).  */
+               if (ALL_STATE) {
+                 lsp = malloc(sizeof *lsp);
+                 if (!lsp)
+                   return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
+                 *lspp = lsp;
+               }
                cp = lsp->fullname;
                cp = mempcpy(cp, tzdirslash, tzdirslashlen);
                cp = mempcpy(cp, name, namelen);
@@ -814,6 +823,13 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
            && !tzfile_changed(fid, &st))
          err = -1;
        else {
+         if (ALL_STATE && !lsp) {
+           lsp = malloc(sizeof *lsp);
+           if (!lsp)
+             return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
+           *lspp = lsp;
+         }
+         up = &lsp->u.u;
          nread = read(fid, up->buf, sizeof up->buf);
          err = tzheadsize <= nread ? 0 : nread < 0 ? errno : EINVAL;
        }
@@ -1069,19 +1085,18 @@ tzloadbody(char const *name, struct state *sp, char 
tzloadflags,
 static int
 tzload(char const *name, struct state *sp, char tzloadflags)
 {
-#ifdef ALL_STATE
-  union local_storage *lsp = malloc(sizeof *lsp);
-  if (!lsp) {
-    return HAVE_MALLOC_ERRNO ? errno : ENOMEM;
-  } else {
-    int err = tzloadbody(name, sp, tzloadflags, lsp);
-    free(lsp);
-    return err;
-  }
+  int r;
+  union local_storage *lsp;
+#if ALL_STATE
+  lsp = NULL;
 #else
   union local_storage ls;
-  return tzloadbody(name, sp, tzloadflags, &ls);
+  lsp = &ls;
 #endif
+  r = tzloadbody(name, sp, tzloadflags, &lsp);
+  if (ALL_STATE)
+    free(lsp);
+  return r;
 }
 
 static const int       mon_lengths[2][MONSPERYEAR] = {
@@ -1741,7 +1756,7 @@ tzset_unlocked(monotime_t now)
          ? 0 < lcl_is_set && strcmp(lcl_TZname, name) == 0
          : lcl_is_set < 0))
     return;
-# ifdef ALL_STATE
+# if ALL_STATE
   if (! sp)
     lclptr = sp = malloc(sizeof *lclptr);
 # endif
@@ -1805,7 +1820,7 @@ gmtcheck(void)
   if (lock() != 0)
     return;
   if (! gmt_is_set) {
-#ifdef ALL_STATE
+#if ALL_STATE
     gmtptr = malloc(sizeof *gmtptr);
 #endif
     if (gmtptr)
-- 
2.51.0

Reply via email to