bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: MT-unsafe time modules


From: Bruno Haible
Subject: Re: MT-unsafe time modules
Date: Fri, 09 Feb 2024 21:22:12 +0100

This patch makes ctime, localtime, tzset, wcsftime multithread-safe.


2024-02-09  Bruno Haible  <bruno@clisp.org>

        ctime, localtime, tzset, wcsftime: Make multithread-safe.
        * lib/ctime.c: Include <wchar.h>.
        (rpl_ctime): Modify _environ and _wenviron without using _putenv.
        * lib/localtime.c: Include <wchar.h>.
        (rpl_localtime): Modify _environ and _wenviron without using _putenv.
        * lib/tzset.c: Include <wchar.h>.
        (rpl_tzset): Modify _environ and _wenviron without using _putenv.
        * lib/wcsftime.c (rpl_wcsftime): Likewise.

diff --git a/lib/ctime.c b/lib/ctime.c
index a11adc5c74..8c54ef463c 100644
--- a/lib/ctime.c
+++ b/lib/ctime.c
@@ -21,6 +21,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+#if defined _WIN32 && ! defined __CYGWIN__
+# include <wchar.h>
+#endif
 
 #undef ctime
 
@@ -52,7 +55,22 @@ rpl_ctime (const time_t *tp)
      responsibility.  */
   const char *tz = getenv ("TZ");
   if (tz != NULL && strchr (tz, '/') != NULL)
-    _putenv ("TZ=");
+    {
+      /* Neutralize it, in a way that is multithread-safe.
+         (If we were to use _putenv ("TZ="), it would free the memory allocated
+         for the environment variable "TZ", and thus other threads that are
+         using the previously fetched value of getenv ("TZ") could crash.)  */
+      char **env = _environ;
+      wchar_t **wenv = _wenviron;
+      if (env != NULL)
+        for (char *s = env; *s != NULL; s++)
+          if (s[0] == 'T' && s[1] == 'Z' && s[2] == '=')
+            s[0] = '$';
+      if (wenv != NULL)
+        for (wchar_t *ws = wenv; *ws != NULL; ws++)
+          if (ws[0] == L'T' && ws[1] == L'Z' && ws[2] == L'=')
+            ws[0] = L'$';
+    }
 #endif
 
   return ctime (tp);
diff --git a/lib/localtime.c b/lib/localtime.c
index bdea1cab10..f0e91ac647 100644
--- a/lib/localtime.c
+++ b/lib/localtime.c
@@ -21,6 +21,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+#if defined _WIN32 && ! defined __CYGWIN__
+# include <wchar.h>
+#endif
 
 #undef localtime
 
@@ -52,7 +55,22 @@ rpl_localtime (const time_t *tp)
      responsibility.  */
   const char *tz = getenv ("TZ");
   if (tz != NULL && strchr (tz, '/') != NULL)
-    _putenv ("TZ=");
+    {
+      /* Neutralize it, in a way that is multithread-safe.
+         (If we were to use _putenv ("TZ="), it would free the memory allocated
+         for the environment variable "TZ", and thus other threads that are
+         using the previously fetched value of getenv ("TZ") could crash.)  */
+      char **env = _environ;
+      wchar_t **wenv = _wenviron;
+      if (env != NULL)
+        for (char *s = env; *s != NULL; s++)
+          if (s[0] == 'T' && s[1] == 'Z' && s[2] == '=')
+            s[0] = '$';
+      if (wenv != NULL)
+        for (wchar_t *ws = wenv; *ws != NULL; ws++)
+          if (ws[0] == L'T' && ws[1] == L'Z' && ws[2] == L'=')
+            ws[0] = L'$';
+    }
 #endif
 
   return localtime (tp);
diff --git a/lib/tzset.c b/lib/tzset.c
index 0eb8c161f4..f307f0c3d1 100644
--- a/lib/tzset.c
+++ b/lib/tzset.c
@@ -24,6 +24,9 @@
 
 #include <stdlib.h>
 #include <string.h>
+#if defined _WIN32 && ! defined __CYGWIN__
+# include <wchar.h>
+#endif
 
 void
 rpl_tzset (void)
@@ -54,7 +57,22 @@ rpl_tzset (void)
      responsibility.  */
   const char *tz = getenv ("TZ");
   if (tz != NULL && strchr (tz, '/') != NULL)
-    _putenv ("TZ=");
+    {
+      /* Neutralize it, in a way that is multithread-safe.
+         (If we were to use _putenv ("TZ="), it would free the memory allocated
+         for the environment variable "TZ", and thus other threads that are
+         using the previously fetched value of getenv ("TZ") could crash.)  */
+      char **env = _environ;
+      wchar_t **wenv = _wenviron;
+      if (env != NULL)
+        for (char *s = env; *s != NULL; s++)
+          if (s[0] == 'T' && s[1] == 'Z' && s[2] == '=')
+            s[0] = '$';
+      if (wenv != NULL)
+        for (wchar_t *ws = wenv; *ws != NULL; ws++)
+          if (ws[0] == L'T' && ws[1] == L'Z' && ws[2] == L'=')
+            ws[0] = L'$';
+    }
 
   /* On native Windows, tzset() is deprecated.  Use _tzset() instead.  See
      
<https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/posix-tzset>
diff --git a/lib/wcsftime.c b/lib/wcsftime.c
index 93e0470dd3..d8b471ab57 100644
--- a/lib/wcsftime.c
+++ b/lib/wcsftime.c
@@ -53,7 +53,22 @@ rpl_wcsftime (wchar_t *buf, size_t bufsize, const wchar_t 
*format, const struct
      responsibility.  */
   const char *tz = getenv ("TZ");
   if (tz != NULL && strchr (tz, '/') != NULL)
-    _putenv ("TZ=");
+    {
+      /* Neutralize it, in a way that is multithread-safe.
+         (If we were to use _putenv ("TZ="), it would free the memory allocated
+         for the environment variable "TZ", and thus other threads that are
+         using the previously fetched value of getenv ("TZ") could crash.)  */
+      char **env = _environ;
+      wchar_t **wenv = _wenviron;
+      if (env != NULL)
+        for (char *s = env; *s != NULL; s++)
+          if (s[0] == 'T' && s[1] == 'Z' && s[2] == '=')
+            s[0] = '$';
+      if (wenv != NULL)
+        for (wchar_t *ws = wenv; *ws != NULL; ws++)
+          if (ws[0] == L'T' && ws[1] == L'Z' && ws[2] == L'=')
+            ws[0] = L'$';
+    }
 #endif
 
   return wcsftime (buf, bufsize, format, tp);






reply via email to

[Prev in Thread] Current Thread [Next in Thread]