From: Viktor Szakats Date: Fri, 12 Dec 2025 23:16:58 +0000 (+0100) Subject: curlx: move `Curl_gmtime()`, use `gmtime_s()` on Windows X-Git-Tag: rc-8_18_0-3~98 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=c6988f9131d8e744c1c4d3ee0c9461e1b51923ed;p=thirdparty%2Fcurl.git curlx: move `Curl_gmtime()`, use `gmtime_s()` on Windows 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 --- diff --git a/lib/altsvc.c b/lib/altsvc.c index c422736fd2..97b4c927d0 100644 --- a/lib/altsvc.c +++ b/lib/altsvc.c @@ -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 diff --git a/lib/curl_setup.h b/lib/curl_setup.h index d34b8a7407..954df47120 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -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 */ diff --git a/lib/curlx/timeval.c b/lib/curlx/timeval.c index ff49d7d274..490dcf0838 100644 --- a/lib/curlx/timeval.c +++ b/lib/curlx/timeval.c @@ -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 /* 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; +} diff --git a/lib/curlx/timeval.h b/lib/curlx/timeval.h index 14819157fd..9cb57af2b7 100644 --- a/lib/curlx/timeval.h +++ b/lib/curlx/timeval.h @@ -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 */ diff --git a/lib/file.c b/lib/file.c index 39642c9340..9d303d4cc3 100644 --- a/lib/file.c +++ b/lib/file.c @@ -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; diff --git a/lib/ftp.c b/lib/ftp.c index 4dedde03aa..f35743017a 100644 --- 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; diff --git a/lib/hsts.c b/lib/hsts.c index 62c4c587df..e1f527dbf9 100644 --- a/lib/hsts.c +++ b/lib/hsts.c @@ -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", diff --git a/lib/http.c b/lib/http.c index d65cba95db..fbedeeebcf 100644 --- a/lib/http.c +++ b/lib/http.c @@ -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; diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index 850daf4139..e815dac729 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -32,10 +32,10 @@ #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 @@ -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; } diff --git a/lib/parsedate.c b/lib/parsedate.c index 0649de454b..43ac676765 100644 --- a/lib/parsedate.c +++ b/lib/parsedate.c @@ -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; -} diff --git a/lib/parsedate.h b/lib/parsedate.h index e5efb53f61..ef2578098d 100644 --- a/lib/parsedate.h +++ b/lib/parsedate.h @@ -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. */ diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index bdea5e58e3..b9e462342a 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -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; diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c index 49c557de03..4841e69088 100644 --- a/lib/vtls/mbedtls.c +++ b/lib/vtls/mbedtls.c @@ -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" diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index 8a845a6ba1..3ebc07ee6f 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -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" diff --git a/m4/curl-functions.m4 b/m4/curl-functions.m4 index 85ccd1ff6c..e872c1c23c 100644 --- a/m4/curl-functions.m4 +++ b/m4/curl-functions.m4 @@ -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; ]]) diff --git a/src/tool_writeout.c b/src/tool_writeout.c index 358c7b39b3..25c9622312 100644 --- a/src/tool_writeout.c +++ b/src/tool_writeout.c @@ -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); }