summaryrefslogtreecommitdiff
path: root/src/interfaces/ecpg
diff options
context:
space:
mode:
authorPeter Eisentraut2024-08-23 05:07:53 +0000
committerPeter Eisentraut2024-08-23 05:43:04 +0000
commita2bbc58f743489784de797d81be37ea309cb0773 (patch)
treec5d9ddf99403cfd2feee359f4497ba11ffae9f8d /src/interfaces/ecpg
parent94a3373ac5c3d2444b2379a3c185b986627c42d4 (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.c11
-rw-r--r--src/interfaces/ecpg/pgtypeslib/timestamp.c3
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;