Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
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)