Avoid statically allocating gmtsub()'s timezone workspace.
authorTom Lane
Tue, 16 Oct 2018 15:50:19 +0000 (11:50 -0400)
committerTom Lane
Tue, 16 Oct 2018 15:50:19 +0000 (11:50 -0400)
localtime.c's "struct state" is a rather large object, ~23KB.  We were
statically allocating one for gmtsub() to use to represent the GMT
timezone, even though that function is not at all heavily used and is
never reached in most backends.  Let's malloc it on-demand, instead.

This does pose the question of how to handle a malloc failure, but
there's already a well-defined error report convention here, ie
set errno and return NULL.

We have but one caller of pg_gmtime in HEAD, and two in back branches,
neither of which were troubling to check for error.  Make them do so.
The possible errors are sufficiently unlikely (out-of-range timestamp,
and now malloc failure) that I think elog() is adequate.

Back-patch to all supported branches to keep our copies of the IANA
timezone code in sync.  This particular change is in a stanza that
already differs from upstream, so it's a wash for maintenance purposes
--- but only as long as we keep the branches the same.

Discussion: https://postgr.es/m/20181015200754[email protected]

src/backend/utils/adt/nabstime.c
src/backend/utils/adt/timestamp.c
src/timezone/localtime.c

index a6d30851df9240b377c49afc12f6176a4caa1213..6ec7ebafb8850e655a2a32328e449588bbef06a7 100644 (file)
@@ -105,6 +105,9 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct pg_tm * tm, char **tzn)
    else
        tx = pg_gmtime(&time);
 
+   if (tx == NULL)
+       elog(ERROR, "could not convert abstime to timestamp: %m");
+
    tm->tm_year = tx->tm_year + 1900;
    tm->tm_mon = tx->tm_mon + 1;
    tm->tm_mday = tx->tm_mday;
index 5ca2fad451faadb7fa36408afe1ee32ea358d633..d24ab8560c8fc5d6d9c948ca7514b05a1413672b 100644 (file)
@@ -2150,6 +2150,9 @@ GetEpochTime(struct pg_tm * tm)
 
    t0 = pg_gmtime(&epoch);
 
+   if (t0 == NULL)
+       elog(ERROR, "could not convert epoch to timestamp: %m");
+
    tm->tm_year = t0->tm_year;
    tm->tm_mon = t0->tm_mon;
    tm->tm_mday = t0->tm_mday;
index 31b06b037f4ffe6590df3e5deca3dfeba718643f..a2260e590ddd9075b8428faeba191f39b1af37ca 100644 (file)
@@ -1328,13 +1328,14 @@ gmtsub(pg_time_t const *timep, int32 offset, struct pg_tm *tmp)
    struct pg_tm *result;
 
    /* GMT timezone state data is kept here */
-   static struct state gmtmem;
-   static bool gmt_is_set = false;
-#define gmtptr     (&gmtmem)
+   static struct state *gmtptr = NULL;
 
-   if (!gmt_is_set)
+   if (gmtptr == NULL)
    {
-       gmt_is_set = true;
+       /* Allocate on first use */
+       gmtptr = (struct state *) malloc(sizeof(struct state));
+       if (gmtptr == NULL)
+           return NULL;        /* errno should be set by malloc */
        gmtload(gmtptr);
    }
    result = timesub(timep, offset, gmtptr, tmp);