diff options
| author | Peter Eisentraut | 2024-08-23 05:07:53 +0000 |
|---|---|---|
| committer | Peter Eisentraut | 2024-08-23 05:43:04 +0000 |
| commit | a2bbc58f743489784de797d81be37ea309cb0773 (patch) | |
| tree | c5d9ddf99403cfd2feee359f4497ba11ffae9f8d /src/interfaces/ecpg | |
| parent | 94a3373ac5c3d2444b2379a3c185b986627c42d4 (diff) | |
thread-safety: gmtime_r(), localtime_r()
Use gmtime_r() and localtime_r() instead of gmtime() and localtime(),
for thread-safety.
There are a few affected calls in libpq and ecpg's libpgtypes, which
are probably effectively bugs, because those libraries already claim
to be thread-safe.
There is one affected call in the backend. Most of the backend
otherwise uses the custom functions pg_gmtime() and pg_localtime(),
which are implemented differently.
While we're here, change the call in the backend to gmtime*() instead
of localtime*(), since for that use time zone behavior is irrelevant,
and this side-steps any questions about when time zones are
initialized by localtime_r() vs localtime().
Portability: gmtime_r() and localtime_r() are in POSIX but are not
available on Windows. Windows has functions gmtime_s() and
localtime_s() that can fulfill the same purpose, so we add some small
wrappers around them. (Note that these *_s() functions are also
different from the *_s() functions in the bounds-checking extension of
C11. We are not using those here.)
On MinGW, you can get the POSIX-style *_r() functions by defining
_POSIX_C_SOURCE appropriately before including <time.h>. This leads
to a conflict at least in plpython because apparently _POSIX_C_SOURCE
gets defined in some header there, and then our replacement
definitions conflict with the system definitions. To avoid that sort
of thing, we now always define _POSIX_C_SOURCE on MinGW and use the
POSIX-style functions here.
Reviewed-by: Stepan Neretin <sncfmgg@gmail.com>
Reviewed-by: Heikki Linnakangas <hlinnaka@iki.fi>
Reviewed-by: Thomas Munro <thomas.munro@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/eba1dc75-298e-4c46-8869-48ba8aad7d70@eisentraut.org
Diffstat (limited to 'src/interfaces/ecpg')
| -rw-r--r-- | src/interfaces/ecpg/pgtypeslib/dt_common.c | 11 | ||||
| -rw-r--r-- | src/interfaces/ecpg/pgtypeslib/timestamp.c | 3 |
2 files changed, 9 insertions, 5 deletions
diff --git a/src/interfaces/ecpg/pgtypeslib/dt_common.c b/src/interfaces/ecpg/pgtypeslib/dt_common.c index ed08088bfe1..0d63fe52c5b 100644 --- a/src/interfaces/ecpg/pgtypeslib/dt_common.c +++ b/src/interfaces/ecpg/pgtypeslib/dt_common.c @@ -949,9 +949,10 @@ int GetEpochTime(struct tm *tm) { struct tm *t0; + struct tm tmbuf; time_t epoch = 0; - t0 = gmtime(&epoch); + t0 = gmtime_r(&epoch, &tmbuf); if (t0) { @@ -973,12 +974,13 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn) { time_t time = (time_t) _time; struct tm *tx; + struct tm tmbuf; errno = 0; if (tzp != NULL) - tx = localtime((time_t *) &time); + tx = localtime_r(&time, &tmbuf); else - tx = gmtime((time_t *) &time); + tx = gmtime_r(&time, &tmbuf); if (!tx) { @@ -2810,9 +2812,10 @@ PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d, /* number of seconds in scan_val.luint_val */ { struct tm *tms; + struct tm tmbuf; time_t et = (time_t) scan_val.luint_val; - tms = gmtime(&et); + tms = gmtime_r(&et, &tmbuf); if (tms) { diff --git a/src/interfaces/ecpg/pgtypeslib/timestamp.c b/src/interfaces/ecpg/pgtypeslib/timestamp.c index 402fae6da67..7cf433266f4 100644 --- a/src/interfaces/ecpg/pgtypeslib/timestamp.c +++ b/src/interfaces/ecpg/pgtypeslib/timestamp.c @@ -129,11 +129,12 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, const char **t if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday)) { #if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE) + struct tm tmbuf; utime = dt / USECS_PER_SEC + ((date0 - date2j(1970, 1, 1)) * INT64CONST(86400)); - tx = localtime(&utime); + tx = localtime_r(&utime, &tmbuf); tm->tm_year = tx->tm_year + 1900; tm->tm_mon = tx->tm_mon + 1; tm->tm_mday = tx->tm_mday; |
