From 8eeaeb4d19388cdcaea94cc8317b25220153a9d7 Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 25 Dec 2022 16:42:17 +0200 Subject: [PATCH 14/14] Replace localtime() calls with new thread safe fc_localtime() See osdn #46228 Signed-off-by: Marko Lindqvist --- client/gui-gtk-2.0/chatline.c | 6 ++-- client/gui-gtk-2.0/luaconsole.c | 6 ++-- client/gui-gtk-3.0/chatline.c | 6 ++-- client/gui-gtk-3.0/luaconsole.c | 6 ++-- client/gui-gtk-3.22/chatline.c | 6 ++-- client/gui-gtk-3.22/luaconsole.c | 6 ++-- common/fc_interface.c | 5 ++- configure.ac | 4 ++- doc/CodingStyle | 3 +- server/console.c | 3 +- server/notify.c | 8 +++-- utility/support.c | 56 ++++++++++++++++++++++++++++---- utility/support.h | 6 ++-- 13 files changed, 84 insertions(+), 37 deletions(-) diff --git a/client/gui-gtk-2.0/chatline.c b/client/gui-gtk-2.0/chatline.c index 7e2dc96293..a2da5fd55f 100644 --- a/client/gui-gtk-2.0/chatline.c +++ b/client/gui-gtk-2.0/chatline.c @@ -912,11 +912,11 @@ void real_output_window_append(const char *astring, if (gui_options.gui_gtk2_show_chat_message_time) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/client/gui-gtk-2.0/luaconsole.c b/client/gui-gtk-2.0/luaconsole.c index 1630c7e7d4..4202ac2dde 100644 --- a/client/gui-gtk-2.0/luaconsole.c +++ b/client/gui-gtk-2.0/luaconsole.c @@ -465,11 +465,11 @@ void real_luaconsole_append(const char *astring, if (gui_options.gui_gtk2_show_chat_message_time) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/client/gui-gtk-3.0/chatline.c b/client/gui-gtk-3.0/chatline.c index 1a4dc9f743..4d508b97cb 100644 --- a/client/gui-gtk-3.0/chatline.c +++ b/client/gui-gtk-3.0/chatline.c @@ -895,11 +895,11 @@ void real_output_window_append(const char *astring, if (GUI_GTK_OPTION(show_chat_message_time)) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/client/gui-gtk-3.0/luaconsole.c b/client/gui-gtk-3.0/luaconsole.c index 6b05c1b2d5..c364d65579 100644 --- a/client/gui-gtk-3.0/luaconsole.c +++ b/client/gui-gtk-3.0/luaconsole.c @@ -474,11 +474,11 @@ void real_luaconsole_append(const char *astring, if (GUI_GTK_OPTION(show_chat_message_time)) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/client/gui-gtk-3.22/chatline.c b/client/gui-gtk-3.22/chatline.c index 722d1ee745..132aef7eda 100644 --- a/client/gui-gtk-3.22/chatline.c +++ b/client/gui-gtk-3.22/chatline.c @@ -895,11 +895,11 @@ void real_output_window_append(const char *astring, if (GUI_GTK_OPTION(show_chat_message_time)) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/client/gui-gtk-3.22/luaconsole.c b/client/gui-gtk-3.22/luaconsole.c index a8d967aaab..d1be41d39e 100644 --- a/client/gui-gtk-3.22/luaconsole.c +++ b/client/gui-gtk-3.22/luaconsole.c @@ -475,11 +475,11 @@ void real_luaconsole_append(const char *astring, if (GUI_GTK_OPTION(show_chat_message_time)) { char timebuf[64]; time_t now; - struct tm *now_tm; + struct tm now_tm; now = time(NULL); - now_tm = localtime(&now); - strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", now_tm); + fc_localtime(&now, &now_tm); + strftime(timebuf, sizeof(timebuf), "[%H:%M:%S] ", &now_tm); gtk_text_buffer_insert(buf, &iter, timebuf, -1); } diff --git a/common/fc_interface.c b/common/fc_interface.c index a90b66e538..4bee314345 100644 --- a/common/fc_interface.c +++ b/common/fc_interface.c @@ -55,6 +55,8 @@ struct functions *fc_interface_funcs(void) **************************************************************************/ void fc_interface_init(void) { + fc_support_init(); + fc_funcs = &fc_functions; /* Test the existence of each required function here! */ @@ -70,8 +72,6 @@ void fc_interface_init(void) fc_funcs_defined = TRUE; - fc_strAPI_init(); - setup_real_activities_array(); } @@ -87,6 +87,5 @@ void free_libfreeciv(void) free_user_home_dir(); free_fileinfo_data(); netfile_free(); - fc_strAPI_free(); fc_support_free(); } diff --git a/configure.ac b/configure.ac index bc580797db..74a9af64b0 100644 --- a/configure.ac +++ b/configure.ac @@ -1649,6 +1649,8 @@ feature_syslua=missing sys_lua=false])])]) fi +AC_CHECK_FUNCS([localtime_r]) + if test "x$sys_lua" != "xtrue" ; then dnl Checks needed for included lua. gl_FUNC_MKSTEMP @@ -1656,7 +1658,7 @@ if test "x$sys_lua" != "xtrue" ; then dnl if only "guessing yes", do not try to use mkstemp, but fallback AC_DEFINE([HAVE_MKSTEMP], [1], [Have working mkstemp]) fi - AC_CHECK_FUNCS([popen pclose _longjmp _setjmp gmtime_r localtime_r]) + AC_CHECK_FUNCS([popen pclose _longjmp _setjmp gmtime_r]) LUA_CFLAGS="-I\$(top_srcdir)/dependencies/lua-5.3/src" LUA_LIBS="\$(top_builddir)/dependencies/lua-5.3/src/liblua.la" diff --git a/doc/CodingStyle b/doc/CodingStyle index bda8000927..5532850791 100644 --- a/doc/CodingStyle +++ b/doc/CodingStyle @@ -517,9 +517,10 @@ modular, so there are some observations to do: utility/support.[ch] module contains low level functions that should be used instead of ones from c-library or other sources. Most of those functions have the 'fc_' prefix in their name. They are more portable (i.e always -available with the freeciv source code) and often more secure that the +available with the freeciv source code) and often more secure than the functions available natively. +- Instead of localtime(), use fc_localtime() ============================================================================ Miscellaneous diff --git a/server/console.c b/server/console.c index bcebdeade0..6de6f1aef7 100644 --- a/server/console.c +++ b/server/console.c @@ -120,10 +120,11 @@ static const char *log_prefix(void) #ifdef LOG_TIMERS char timestr[32]; time_t timestamp; + struct tm tr; time(×tamp); strftime(timestr, sizeof(timestr), "%Y/%m/%d %H:%M:%S", - localtime(×tamp)); + fc_localtime(×tamp, &tr)); fc_snprintf(buf, sizeof(buf), "T%03d - %s", game.info.turn, timestr); diff --git a/server/notify.c b/server/notify.c index faf046ccdd..172e0ea37b 100644 --- a/server/notify.c +++ b/server/notify.c @@ -748,7 +748,7 @@ static bool event_cache_match(const struct event_cache_data *pdata, } /************************************************************************** - Send all available events. If include_public is TRUE, also fully global + Send all available events. If include_public is TRUE, also fully global message will be sent. **************************************************************************/ void send_pending_events(struct connection *pconn, bool include_public) @@ -762,9 +762,11 @@ void send_pending_events(struct connection *pconn, bool include_public) if (event_cache_match(pdata, pplayer, is_global_observer, include_public)) { if (game.server.event_cache.info) { - /* add turn and time to the message */ + struct tm tr; + + /* Add turn and time to the message */ strftime(timestr, sizeof(timestr), "%H:%M:%S", - localtime(&pdata->timestamp)); + fc_localtime(&pdata->timestamp, &tr)); pcm = pdata->packet; fc_snprintf(pcm.message, sizeof(pcm.message), "(T%d - %s) %s", pdata->packet.turn, timestr, pdata->packet.message); diff --git a/utility/support.c b/utility/support.c index 730742461f..b7b3970116 100644 --- a/utility/support.c +++ b/utility/support.c @@ -149,7 +149,7 @@ static void icu_buffers_increase(void) /*************************************************************** Initialize string handling API ***************************************************************/ -void fc_strAPI_init(void) +static void fc_strAPI_init(void) { if (icu_buffer_uchars == 0) { fc_init_mutex(&icu_buffer_mutex); @@ -160,7 +160,7 @@ void fc_strAPI_init(void) /*************************************************************** Free string handling API resources ***************************************************************/ -void fc_strAPI_free(void) +static void fc_strAPI_free(void) { if (icu_buffer1 != NULL) { free(icu_buffer1); @@ -803,9 +803,13 @@ size_t fc_strlcpy(char *dest, const char *src, size_t n) #ifndef HAVE_WORKING_VSNPRINTF static char *vsnprintf_buf = NULL; -fc_mutex vsnprintf_mutex; +static fc_mutex vsnprintf_mutex; #endif /* HAVE_WORKING_VSNPRINTF */ +#ifndef HAVE_LOCALTIME_R +static fc_mutex localtime_mutex; +#endif /* HAVE_LOCALTIME_R */ + /************************************************************************//** fc_strlcat() provides utf-8 version of (non-standard) function strlcat() It is intended as more user-friendly version of strncat(), in particular @@ -906,19 +910,19 @@ int fc_vsnprintf(char *str, size_t n, const char *format, va_list ap) exit(EXIT_FAILURE); } + fc_allocate_mutex(&vsnprintf_mutex); + if (vsnprintf_buf == NULL) { - fc_init_mutex(&vsnprintf_mutex); vsnprintf_buf = malloc(VSNP_BUF_SIZE); if (vsnprintf_buf == NULL) { fprintf(stderr, "Could not allocate %i bytes for vsnprintf() " "replacement.", VSNP_BUF_SIZE); + fc_release_mutex(&vsnprintf_mutex); exit(EXIT_FAILURE); } } - fc_allocate_mutex(&vsnprintf_mutex); - vsnprintf_buf[VSNP_BUF_SIZE - 1] = '\0'; #ifdef HAVE_VSNPRINTF @@ -1291,6 +1295,22 @@ const char *fc_basename(const char *path) return basename(buf); } +/***************************************************************** + Thread safe localtime() replacement +*****************************************************************/ +struct tm *fc_localtime(const time_t *timep, struct tm *result) +{ +#ifdef HAVE_LOCALTIME_R + return localtime_r(timep, result); +#else /* HAVE_LOCALTIME_R */ + fc_allocate_mutex(&localtime_mutex); + memcpy(result, localtime(timep), sizeof(struct tm)); + fc_release_mutex(&localtime_mutex); + + return result; +#endif /* HAVE_LOCALTIME_R */ +} + /***************************************************************** Set quick_exit() callback if possible. *****************************************************************/ @@ -1303,6 +1323,22 @@ int fc_at_quick_exit(void (*func)(void)) #endif /* HAVE_AT_QUICK_EXIT */ } +/***************************************************************** + Initialize support module. +*****************************************************************/ +void fc_support_init(void) +{ + fc_strAPI_init(); + +#ifndef HAVE_WORKING_VSNPRINTF + fc_init_mutex(&vsnprintf_mutex); +#endif /* HAVE_WORKING_VSNPRINTF */ + +#ifndef HAVE_LOCALTIME_R + fc_init_mutex(&localtime_mutex); +#endif /* HAVE_LOCALTIME_R */ +} + /***************************************************************** Free misc resources allocated by the support module. *****************************************************************/ @@ -1312,7 +1348,13 @@ void fc_support_free(void) if (vsnprintf_buf != NULL) { free(vsnprintf_buf); vsnprintf_buf = NULL; - fc_destroy_mutex(&vsnprintf_mutex); } + fc_destroy_mutex(&vsnprintf_mutex); #endif /* HAVE_WORKING_VSNPRINTF */ + +#ifndef HAVE_LOCALTIME_R + fc_destroy_mutex(&localtime_mutex); +#endif /* HAVE_LOCALTIME_R */ + + fc_strAPI_free(); } diff --git a/utility/support.h b/utility/support.h index 4330db41c7..e4335b9fee 100644 --- a/utility/support.h +++ b/utility/support.h @@ -123,9 +123,7 @@ int fc_strcasecmp(const char *str0, const char *str1); int fc_strncasecmp(const char *str0, const char *str1, size_t n); int fc_strncasequotecmp(const char *str0, const char *str1, size_t n); -void fc_strAPI_init(void); -void fc_strAPI_free(void); - +void fc_support_init(void); void fc_support_free(void); size_t effectivestrlenquote(const char *str); @@ -192,6 +190,8 @@ char fc_tolower(char c); const char *fc_basename(const char *path); +struct tm *fc_localtime(const time_t *timep, struct tm *result); + /************************************************************************//** Return whether the program is currently running on a bigendian system. ****************************************************************************/ -- 2.35.1