aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2018-10-16 11:50:18 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2018-10-16 11:50:18 -0400
commitd112682373784b72bb293f6b78b7d8cec0c0aa93 (patch)
treeb5938a122aeed77caf3f2fd60a24f1fd50db3baf
parent19f20081df059fef87e14c8e953669bd173dd7f1 (diff)
downloadpostgresql-d112682373784b72bb293f6b78b7d8cec0c0aa93.tar.gz
postgresql-d112682373784b72bb293f6b78b7d8cec0c0aa93.zip
Avoid statically allocating gmtsub()'s timezone workspace.
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.7y7zfuzsoux2c4ya@alap3.anarazel.de
-rw-r--r--src/backend/utils/adt/nabstime.c3
-rw-r--r--src/backend/utils/adt/timestamp.c3
-rw-r--r--src/timezone/localtime.c11
3 files changed, 12 insertions, 5 deletions
diff --git a/src/backend/utils/adt/nabstime.c b/src/backend/utils/adt/nabstime.c
index fae97135dbb..af430f2d2c3 100644
--- a/src/backend/utils/adt/nabstime.c
+++ b/src/backend/utils/adt/nabstime.c
@@ -106,6 +106,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;
diff --git a/src/backend/utils/adt/timestamp.c b/src/backend/utils/adt/timestamp.c
index 1d75caebe17..4dac27e8491 100644
--- a/src/backend/utils/adt/timestamp.c
+++ b/src/backend/utils/adt/timestamp.c
@@ -1988,6 +1988,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;
diff --git a/src/timezone/localtime.c b/src/timezone/localtime.c
index 31b06b037f4..a2260e590dd 100644
--- a/src/timezone/localtime.c
+++ b/src/timezone/localtime.c
@@ -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);