Skip to content

Commit a2bbc58

Browse files
committed
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
1 parent 94a3373 commit a2bbc58

File tree

7 files changed

+33
-7
lines changed

7 files changed

+33
-7
lines changed

meson.build

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -268,6 +268,10 @@ elif host_system == 'windows'
268268
exesuffix = '.exe'
269269
dlsuffix = '.dll'
270270
library_path_var = ''
271+
if cc.get_id() != 'msvc'
272+
# define before including <time.h> for getting localtime_r() etc. on MinGW
273+
cppflags += '-D_POSIX_C_SOURCE'
274+
endif
271275

272276
export_file_format = 'win'
273277
export_file_suffix = 'def'

src/backend/utils/adt/pg_locale.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,7 @@ cache_locale_time(void)
826826
char *bufptr;
827827
time_t timenow;
828828
struct tm *timeinfo;
829+
struct tm timeinfobuf;
829830
bool strftimefail = false;
830831
int encoding;
831832
int i;
@@ -876,7 +877,7 @@ cache_locale_time(void)
876877

877878
/* We use times close to current time as data for strftime(). */
878879
timenow = time(NULL);
879-
timeinfo = localtime(&timenow);
880+
timeinfo = gmtime_r(&timenow, &timeinfobuf);
880881

881882
/* Store the strftime results in MAX_L10N_DATA-sized portions of buf[] */
882883
bufptr = buf;

src/include/port/win32_port.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -420,6 +420,19 @@ extern int _pglstat64(const char *name, struct stat *buf);
420420
*/
421421
#define strtok_r strtok_s
422422

423+
/*
424+
* Supplement to <time.h>.
425+
*/
426+
#ifdef _MSC_VER
427+
/*
428+
* MinGW has these functions if _POSIX_C_SOURCE is defined. Third-party
429+
* libraries might do that, so to avoid clashes we get ahead of it and define
430+
* it ourselves and use the system functions provided by MinGW.
431+
*/
432+
#define gmtime_r(clock, result) (gmtime_s(result, clock) ? NULL : (result))
433+
#define localtime_r(clock, result) (localtime_s(result, clock) ? NULL : (result))
434+
#endif
435+
423436
/*
424437
* Locale stuff.
425438
*

src/interfaces/ecpg/pgtypeslib/dt_common.c

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -949,9 +949,10 @@ int
949949
GetEpochTime(struct tm *tm)
950950
{
951951
struct tm *t0;
952+
struct tm tmbuf;
952953
time_t epoch = 0;
953954

954-
t0 = gmtime(&epoch);
955+
t0 = gmtime_r(&epoch, &tmbuf);
955956

956957
if (t0)
957958
{
@@ -973,12 +974,13 @@ abstime2tm(AbsoluteTime _time, int *tzp, struct tm *tm, char **tzn)
973974
{
974975
time_t time = (time_t) _time;
975976
struct tm *tx;
977+
struct tm tmbuf;
976978

977979
errno = 0;
978980
if (tzp != NULL)
979-
tx = localtime((time_t *) &time);
981+
tx = localtime_r(&time, &tmbuf);
980982
else
981-
tx = gmtime((time_t *) &time);
983+
tx = gmtime_r(&time, &tmbuf);
982984

983985
if (!tx)
984986
{
@@ -2810,9 +2812,10 @@ PGTYPEStimestamp_defmt_scan(char **str, char *fmt, timestamp * d,
28102812
/* number of seconds in scan_val.luint_val */
28112813
{
28122814
struct tm *tms;
2815+
struct tm tmbuf;
28132816
time_t et = (time_t) scan_val.luint_val;
28142817

2815-
tms = gmtime(&et);
2818+
tms = gmtime_r(&et, &tmbuf);
28162819

28172820
if (tms)
28182821
{

src/interfaces/ecpg/pgtypeslib/timestamp.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,12 @@ timestamp2tm(timestamp dt, int *tzp, struct tm *tm, fsec_t *fsec, const char **t
129129
if (IS_VALID_UTIME(tm->tm_year, tm->tm_mon, tm->tm_mday))
130130
{
131131
#if defined(HAVE_STRUCT_TM_TM_ZONE) || defined(HAVE_INT_TIMEZONE)
132+
struct tm tmbuf;
132133

133134
utime = dt / USECS_PER_SEC +
134135
((date0 - date2j(1970, 1, 1)) * INT64CONST(86400));
135136

136-
tx = localtime(&utime);
137+
tx = localtime_r(&utime, &tmbuf);
137138
tm->tm_year = tx->tm_year + 1900;
138139
tm->tm_mon = tx->tm_mon + 1;
139140
tm->tm_mday = tx->tm_mday;

src/interfaces/libpq/fe-trace.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ pqTraceFormatTimestamp(char *timestr, size_t ts_len)
8181
{
8282
struct timeval tval;
8383
time_t now;
84+
struct tm tmbuf;
8485

8586
gettimeofday(&tval, NULL);
8687

@@ -93,7 +94,7 @@ pqTraceFormatTimestamp(char *timestr, size_t ts_len)
9394
now = tval.tv_sec;
9495
strftime(timestr, ts_len,
9596
"%Y-%m-%d %H:%M:%S",
96-
localtime(&now));
97+
localtime_r(&now, &tmbuf));
9798
/* append microseconds */
9899
snprintf(timestr + strlen(timestr), ts_len - strlen(timestr),
99100
".%06u", (unsigned int) (tval.tv_usec));

src/template/win32

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
# src/template/win32
22

3+
# define before including <time.h> for getting localtime_r() etc. on MinGW
4+
CPPFLAGS="$CPPFLAGS -D_POSIX_C_SOURCE"
5+
36
# Extra CFLAGS for code that will go into a shared library
47
CFLAGS_SL=""
58

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy