]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
curlx: move `Curl_gmtime()`, use `gmtime_s()` on Windows
authorViktor Szakats <commit@vsz.me>
Fri, 12 Dec 2025 23:16:58 +0000 (00:16 +0100)
committerViktor Szakats <commit@vsz.me>
Tue, 16 Dec 2025 13:30:05 +0000 (14:30 +0100)
Move `Curl_gmtime()` to curlx and rename to `curlx_gmtime()`. Then call
the internal wrapper also from the curl tool, to avoid using the banned
`gmtime()` directly, and using better, thread-safe alternatives when
available.

Windows `gmtime_s()` requires mingw-w64 v4+ or MSVC. Use local
workaround to also support mingw-w64 v3. `gmtime_s()` also makes
defining `_CRT_SECURE_NO_WARNINGS` unnecessary.

Also:
- lib: drop unused `parsedate.h` includes.
- drop redundant cast from `gmtime_r()` result.
- autotools: reverse condition in the proto detection to avoid
  misleading readers. (the condition plays no role in detection.)
- note Windows XP's default `msvcrt.dll` doesn't offer secure CRT APIs.
  XP likely needs a newer version of this DLL, or may not run.

Refs:
https://learn.microsoft.com/cpp/c-runtime-library/reference/gmtime-gmtime32-gmtime64
https://learn.microsoft.com/cpp/c-runtime-library/reference/gmtime-s-gmtime32-s-gmtime64-s
https://pubs.opengroup.org/onlinepubs/9799919799/functions/gmtime.html
https://linux.die.net/man/3/gmtime_r

Ref: #19957 (for `localtime_r()`)
Follow-up to 54d9f060b4b0a8fb5fa006813e4db1ca5c1a07e8
Closes #19955

16 files changed:
lib/altsvc.c
lib/curl_setup.h
lib/curlx/timeval.c
lib/curlx/timeval.h
lib/file.c
lib/ftp.c
lib/hsts.c
lib/http.c
lib/http_aws_sigv4.c
lib/parsedate.c
lib/parsedate.h
lib/vtls/gtls.c
lib/vtls/mbedtls.c
lib/vtls/wolfssl.c
m4/curl-functions.m4
src/tool_writeout.c

index c422736fd230f5f865b5c6cb5e88d468f02b31a8..97b4c927d0c3adeb3cc5350aa060bf93597c13a1 100644 (file)
@@ -40,6 +40,7 @@
 #include "strdup.h"
 #include "curlx/inet_pton.h"
 #include "curlx/strparse.h"
+#include "curlx/timeval.h"
 #include "connect.h"
 
 #define MAX_ALTSVC_LINE    4095
@@ -241,7 +242,7 @@ static CURLcode altsvc_out(struct altsvc *as, FILE *fp)
   const char *dst6_post = "";
   const char *src6_pre = "";
   const char *src6_post = "";
-  CURLcode result = Curl_gmtime(as->expires, &stamp);
+  CURLcode result = curlx_gmtime(as->expires, &stamp);
   if(result)
     return result;
 #ifdef USE_IPV6
index d34b8a7407ceb7155668f45af799f12dd175a1d2..954df47120984f47b5b8a89a1630a038cb4f8df0 100644 (file)
@@ -94,7 +94,7 @@
 #define _CRT_NONSTDC_NO_DEPRECATE  /* for close(), fileno(), unlink(), etc. */
 #endif
 #ifndef _CRT_SECURE_NO_WARNINGS
-#define _CRT_SECURE_NO_WARNINGS  /* for getenv(), gmtime(), strcpy(),
+#define _CRT_SECURE_NO_WARNINGS  /* for getenv(), strcpy(),
                                     in tests: localtime(), sscanf() */
 #endif
 #endif /* _MSC_VER */
index ff49d7d274649eb264330e4fe6be7c25c83f5496..490dcf0838e7b8e626a32b4edcdc0ad57298128a 100644 (file)
@@ -258,3 +258,39 @@ timediff_t curlx_timediff_us(struct curltime newer, struct curltime older)
     return TIMEDIFF_T_MIN;
   return diff * 1000000 + newer.tv_usec - older.tv_usec;
 }
+
+#if defined(__MINGW32__) && (__MINGW64_VERSION_MAJOR <= 3)
+#include <sec_api/time_s.h>  /* for _gmtime32_s(), _gmtime64_s() */
+#ifdef _USE_32BIT_TIME_T
+#define gmtime_s _gmtime32_s
+#else
+#define gmtime_s _gmtime64_s
+#endif
+#endif
+
+/*
+ * curlx_gmtime() is a gmtime() replacement for portability. Do not use
+ * the gmtime_s(), gmtime_r() or gmtime() functions anywhere else but here.
+ */
+CURLcode curlx_gmtime(time_t intime, struct tm *store)
+{
+#ifdef _WIN32
+  if(gmtime_s(store, &intime)) /* thread-safe */
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#elif defined(HAVE_GMTIME_R)
+  const struct tm *tm;
+  tm = gmtime_r(&intime, store); /* thread-safe */
+  if(!tm)
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#else
+  const struct tm *tm;
+  /* !checksrc! disable BANNEDFUNC 1 */
+  tm = gmtime(&intime); /* not thread-safe */
+  if(tm)
+    *store = *tm; /* copy the pointed struct to the local copy */
+  else
+    return CURLE_BAD_FUNCTION_ARGUMENT;
+#endif
+
+  return CURLE_OK;
+}
index 14819157fd49172fa92470bddb235774dab2f3f5..9cb57af2b73f6a7a60b792f11d255a932b8f1fb9 100644 (file)
@@ -65,4 +65,6 @@ timediff_t curlx_timediff_ceil_ms(struct curltime newer,
  */
 timediff_t curlx_timediff_us(struct curltime newer, struct curltime older);
 
+CURLcode curlx_gmtime(time_t intime, struct tm *store);
+
 #endif /* HEADER_CURL_TIMEVAL_H */
index 39642c9340c4bb663e4d7e4b98bec555b3f0b4bb..9d303d4cc34cbab4621924f4d2b419bb8f715f1d 100644 (file)
@@ -65,6 +65,7 @@
 #include "url.h"
 #include "parsedate.h" /* for the week day and month names */
 #include "curlx/fopen.h"
+#include "curlx/timeval.h"
 #include "curlx/warnless.h"
 #include "curl_range.h"
 
@@ -490,7 +491,7 @@ static CURLcode file_do(struct Curl_easy *data, bool *done)
     }
 
     filetime = (time_t)statbuf.st_mtime;
-    result = Curl_gmtime(filetime, &buffer);
+    result = curlx_gmtime(filetime, &buffer);
     if(result)
       return result;
 
index 4dedde03aaecef74876c2880d4b45ab2034e041d..f35743017a65de60dcc504802aa844a0b3d7d9d7 100644 (file)
--- a/lib/ftp.c
+++ b/lib/ftp.c
@@ -71,6 +71,7 @@
 #include "strdup.h"
 #include "curlx/strerr.h"
 #include "curlx/strparse.h"
+#include "curlx/timeval.h"
 
 #ifndef NI_MAXHOST
 #define NI_MAXHOST 1025
@@ -2110,7 +2111,7 @@ static CURLcode ftp_state_mdtm_resp(struct Curl_easy *data,
       struct tm buffer;
       const struct tm *tm = &buffer;
 
-      result = Curl_gmtime(filetime, &buffer);
+      result = curlx_gmtime(filetime, &buffer);
       if(result)
         return result;
 
index 62c4c587dfb334dfe5a7265d778bd9cb3eeb6ac9..e1f527dbf9f7954b5ba38f20b61495364481c04c 100644 (file)
@@ -40,6 +40,7 @@
 #include "curl_share.h"
 #include "strdup.h"
 #include "curlx/strparse.h"
+#include "curlx/timeval.h"
 
 #define MAX_HSTS_LINE    4095
 #define MAX_HSTS_HOSTLEN 2048
@@ -288,7 +289,7 @@ static CURLcode hsts_push(struct Curl_easy *data,
   e.includeSubDomains = sts->includeSubDomains;
 
   if(sts->expires != TIME_T_MAX) {
-    result = Curl_gmtime((time_t)sts->expires, &stamp);
+    result = curlx_gmtime((time_t)sts->expires, &stamp);
     if(result)
       return result;
 
@@ -311,7 +312,7 @@ static CURLcode hsts_out(struct stsentry *sts, FILE *fp)
 {
   struct tm stamp;
   if(sts->expires != TIME_T_MAX) {
-    CURLcode result = Curl_gmtime((time_t)sts->expires, &stamp);
+    CURLcode result = curlx_gmtime((time_t)sts->expires, &stamp);
     if(result)
       return result;
     curl_mfprintf(fp, "%s%s \"%d%02d%02d %02d:%02d:%02d\"\n",
index d65cba95dbcfa7936e83e8d6bbf2dccd6ef67838..fbedeeebcf5eeafd03fc81fbc8fc2ed72ae3bf0b 100644 (file)
@@ -87,6 +87,7 @@
 #include "bufref.h"
 #include "curl_ctype.h"
 #include "curlx/strparse.h"
+#include "curlx/timeval.h"
 
 /*
  * Forward declarations.
@@ -1786,7 +1787,7 @@ CURLcode Curl_add_timecondition(struct Curl_easy *data,
     /* no condition was asked for */
     return CURLE_OK;
 
-  result = Curl_gmtime(data->set.timevalue, &keeptime);
+  result = curlx_gmtime(data->set.timevalue, &keeptime);
   if(result) {
     failf(data, "Invalid TIMEVALUE");
     return result;
index 850daf4139520a6f96dcff98f825716c6effc9ca..e815dac72940949df30161f901da964f7c6429c6 100644 (file)
 #include "http_aws_sigv4.h"
 #include "curl_sha256.h"
 #include "transfer.h"
-#include "parsedate.h"
 #include "sendf.h"
 #include "escape.h"
 #include "curlx/strparse.h"
+#include "curlx/timeval.h"
 
 #include <time.h>
 
@@ -806,7 +806,7 @@ CURLcode Curl_output_aws_sigv4(struct Curl_easy *data)
 #else
   clock = time(NULL);
 #endif
-  result = Curl_gmtime(clock, &tm);
+  result = curlx_gmtime(clock, &tm);
   if(result) {
     goto fail;
   }
index 0649de454b4c3dcaff537d88226635d2d71ae77b..43ac676765b9cc83a2fd67113e3124c3846cd30a 100644 (file)
@@ -598,27 +598,3 @@ int Curl_getdate_capped(const char *p, time_t *tp)
   int rc = parsedate(p, tp);
   return (rc == PARSEDATE_FAIL);
 }
-
-/*
- * Curl_gmtime() is a gmtime() replacement for portability. Do not use the
- * gmtime_r() or gmtime() functions anywhere else but here.
- *
- */
-
-CURLcode Curl_gmtime(time_t intime, struct tm *store)
-{
-  const struct tm *tm;
-#ifdef HAVE_GMTIME_R
-  /* thread-safe version */
-  tm = (struct tm *)gmtime_r(&intime, store);
-#else
-  /* !checksrc! disable BANNEDFUNC 1 */
-  tm = gmtime(&intime);
-  if(tm)
-    *store = *tm; /* copy the pointed struct to the local copy */
-#endif
-
-  if(!tm)
-    return CURLE_BAD_FUNCTION_ARGUMENT;
-  return CURLE_OK;
-}
index e5efb53f617d0b16d2bd7c132c9cdefc42d1a0e1..ef2578098d5f402a550cb4861c0f54f436d2cd46 100644 (file)
@@ -27,8 +27,6 @@
 extern const char * const Curl_wkday[7];
 extern const char * const Curl_month[12];
 
-CURLcode Curl_gmtime(time_t intime, struct tm *store);
-
 /* Curl_getdate_capped() differs from curl_getdate() in that this returns
    TIME_T_MAX in case the parsed time value was too big, instead of an
    error. */
index bdea5e58e31e091cf86798e5d7b566f9b08f0437..b9e462342a4843216a1425d2ddf2f98ce7bfb6db 100644 (file)
@@ -56,6 +56,7 @@
 #include "../select.h"
 #include "../strdup.h"
 #include "../curlx/fopen.h"
+#include "../curlx/timeval.h"
 #include "../curlx/warnless.h"
 #include "x509asn1.h"
 #include "../multiif.h"
@@ -178,7 +179,7 @@ static void showtime(struct Curl_easy *data, const char *text, time_t stamp)
   struct tm buffer;
   const struct tm *tm = &buffer;
   char str[96];
-  CURLcode result = Curl_gmtime(stamp, &buffer);
+  CURLcode result = curlx_gmtime(stamp, &buffer);
   if(result)
     return;
 
index 49c557de0311bdaf83785304a1d9900aa4585fd9..4841e690888e7c61553d8274bb09dae88a844930 100644 (file)
@@ -67,7 +67,6 @@
 #include "vtls_int.h"
 #include "vtls_scache.h"
 #include "x509asn1.h"
-#include "../parsedate.h"
 #include "../connect.h" /* for the connect timeout */
 #include "../select.h"
 #include "../multiif.h"
index 8a845a6ba1d957e25eaaf6d45b1ee094508f5bcb..3ebc07ee6faf4bc18047fcef59cda70aa4998701 100644 (file)
@@ -63,7 +63,6 @@
 #include "vtls_int.h"
 #include "vtls_scache.h"
 #include "keylog.h"
-#include "../parsedate.h"
 #include "../connect.h" /* for the connect timeout */
 #include "../progress.h"
 #include "../select.h"
index 85ccd1ff6ca9cfbbddb4396cb74b92fbed5d58c3..e872c1c23c95a1a0ac0e29f859f23e9c54027329 100644 (file)
@@ -2134,7 +2134,7 @@ AC_DEFUN([CURL_CHECK_FUNC_GMTIME_R], [
       ]],[[
         time_t tm = 1170352587;
         struct tm result;
-        if(gmtime_r(&tm, &result) != 0)
+        if(gmtime_r(&tm, &result) == 0)
           return 1;
         (void)result;
       ]])
index 358c7b39b3f93e538de6b1b2a5b224c9c628a9a0..25c9622312bbc5b7cec2eeb698fdde016c1ea525 100644 (file)
@@ -548,7 +548,6 @@ static const char *outtime(const char *ptr, /* %time{ ... */
   ptr += 6;
   end = strchr(ptr, '}');
   if(end) {
-    struct tm *utc;
     struct dynbuf format;
     char output[256]; /* max output time length */
 #ifdef HAVE_GETTIMEOFDAY
@@ -602,10 +601,10 @@ static const char *outtime(const char *ptr, /* %time{ ... */
         result = curlx_dyn_addn(&format, &ptr[i], 1);
     }
     if(!result) {
-      /* !checksrc! disable BANNEDFUNC 1 */
-      utc = gmtime(&secs);
-      if(curlx_dyn_len(&format) && utc &&
-         strftime(output, sizeof(output), curlx_dyn_ptr(&format), utc))
+      struct tm utc;
+      result = curlx_gmtime(secs, &utc);
+      if(curlx_dyn_len(&format) && !result &&
+         strftime(output, sizeof(output), curlx_dyn_ptr(&format), &utc))
         fputs(output, stream);
       curlx_dyn_free(&format);
     }