From 1359ebabad9e9264b8d73e855ad09c4af456b12f Mon Sep 17 00:00:00 2001 From: Marko Lindqvist Date: Sun, 25 Dec 2022 16:30:19 +0200 Subject: [PATCH 24/24] Replace localtime() calls with new thread safe fc_localtime() See osdn #46228 Signed-off-by: Marko Lindqvist --- 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 ++-- client/gui-gtk-4.0/chatline.c | 6 ++-- client/gui-gtk-4.0/luaconsole.c | 6 ++-- common/fc_interface.c | 5 ++- configure.ac | 4 ++- doc/CodingStyle | 3 +- gen_headers/meson_fc_config.h.in | 3 ++ meson.build | 3 +- server/console.c | 3 +- server/notify.c | 8 +++-- utility/support.c | 56 ++++++++++++++++++++++++++++---- utility/support.h | 6 ++-- 15 files changed, 89 insertions(+), 38 deletions(-) diff --git a/client/gui-gtk-3.0/chatline.c b/client/gui-gtk-3.0/chatline.c index 08414f072d..a95884e8f1 100644 --- a/client/gui-gtk-3.0/chatline.c +++ b/client/gui-gtk-3.0/chatline.c @@ -894,11 +894,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 d1a225bac3..8c55168131 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 07752ab2a8..611ad05f43 100644 --- a/client/gui-gtk-3.22/chatline.c +++ b/client/gui-gtk-3.22/chatline.c @@ -894,11 +894,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 6d1683d6a1..84b3370f15 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/client/gui-gtk-4.0/chatline.c b/client/gui-gtk-4.0/chatline.c index ed9dac511d..13754ab62d 100644 --- a/client/gui-gtk-4.0/chatline.c +++ b/client/gui-gtk-4.0/chatline.c @@ -911,11 +911,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-4.0/luaconsole.c b/client/gui-gtk-4.0/luaconsole.c index 120c4442a4..e4267caab5 100644 --- a/client/gui-gtk-4.0/luaconsole.c +++ b/client/gui-gtk-4.0/luaconsole.c @@ -484,11 +484,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 e88c732b60..9365a79242 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 9f35cc1bb6..9beba65492 100644 --- a/configure.ac +++ b/configure.ac @@ -1724,6 +1724,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 @@ -1731,7 +1733,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.4/src" LUA_LIBS="\$(top_builddir)/dependencies/lua-5.4/src/liblua.la" diff --git a/doc/CodingStyle b/doc/CodingStyle index 2a99b44580..142cf1d13d 100644 --- a/doc/CodingStyle +++ b/doc/CodingStyle @@ -524,9 +524,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/gen_headers/meson_fc_config.h.in b/gen_headers/meson_fc_config.h.in index 3730450409..6ce3397027 100644 --- a/gen_headers/meson_fc_config.h.in +++ b/gen_headers/meson_fc_config.h.in @@ -367,6 +367,9 @@ /* vsnprintf() available */ #mesondefine HAVE_VSNPRINTF +/* localtime_r() available */ +#mesondefine HAVE_LOCALTIME_R + /* _longjmp() available */ #mesondefine HAVE__LONGJMP diff --git a/meson.build b/meson.build index b402d9a01c..c8fd00e47e 100644 --- a/meson.build +++ b/meson.build @@ -283,7 +283,8 @@ priv_functions = [ 'fcntl', 'ioctl', 'vsnprintf', - 'va_copy' + 'va_copy', + 'localtime_r' ] foreach func : priv_functions diff --git a/server/console.c b/server/console.c index 3b2dd25011..0586154b7c 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 5a3bfe552e..cd372613d9 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 8922467207..8b6921e699 100644 --- a/utility/support.c +++ b/utility/support.c @@ -118,9 +118,13 @@ fc_mutex icu_buffer_mutex; #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 */ + /************************************************************************//** Initial allocation of string comparison buffers. ****************************************************************************/ @@ -154,7 +158,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); @@ -165,7 +169,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); @@ -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