ctime, localtime, tzset, wcsftime: Make multithread-safe.
authorBruno Haible <bruno@clisp.org>
Fri, 9 Feb 2024 19:42:53 +0000 (20:42 +0100)
committerBruno Haible <bruno@clisp.org>
Fri, 9 Feb 2024 19:42:53 +0000 (20:42 +0100)
* 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.

ChangeLog
lib/ctime.c
lib/localtime.c
lib/tzset.c
lib/wcsftime.c

index 6d72ea28b1664a5fe250fe6740e43284a15a0110..7ada620262eb957c0472dc34607464964d91e510 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+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.
+
 2024-02-09  Bruno Haible  <bruno@clisp.org>
 
        strftime: Remove module, deprecated in 2017.
index a11adc5c74160eb03d0981f54a28f5ecd60ed672..8c54ef463c0065ac0080e59338538791935e030e 100644 (file)
@@ -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);
index bdea1cab102b88594cf926515449f21874800278..f0e91ac6477219b1d0fb3783711aae62fd7dd906 100644 (file)
@@ -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);
index 0eb8c161f4a5d488f4a61f6b73d27a42a90db7fa..f307f0c3d1baa0663ce8f1bc9d769b00b88d3c41 100644 (file)
@@ -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>
index 93e0470dd319c9f7d939fda7218840acc8ab2d2a..d8b471ab57dd5205668c181d9de45600a952db22 100644 (file)
@@ -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);