From ef663d64d72e08b4e36e5534d5b20a1e3b6762dc Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Thu, 6 Feb 2025 15:36:22 +0100 Subject: [PATCH] Fix GH-17717: Socket maximum timeout of 2147 seconds? The fix for GH-16809[1] used a way too small timeout maximum on Windows. We correct this. However, later on the timeout is applied to the current timestamp, so we would need to take that into account, but due to the elapsed time between the check and the actual network request, this could not be precise, and the resulting error message would be confusing, since after the developer would adjust the timeout to the reported maximum, the check would fail again, now reporting a lower maximum timeout. Thus we silently cap the value in `php_network_set_limit_time()` to avoid undefined behavior, and are not picky about the usec value (we just assume a second more), since there is a bigger issue, namely that we hit the Y2038 problem on Windows. [1] --- ext/standard/http_fopen_wrapper.c | 2 +- main/network.c | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ext/standard/http_fopen_wrapper.c b/ext/standard/http_fopen_wrapper.c index fb987c82e5cc2..e4c63a957003e 100644 --- a/ext/standard/http_fopen_wrapper.c +++ b/ext/standard/http_fopen_wrapper.c @@ -219,7 +219,7 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper, #ifndef PHP_WIN32 const double timeoutmax = (double) PHP_TIMEOUT_ULL_MAX / 1000000.0; #else - const double timeoutmax = (double) LONG_MAX / 1000000.0; + const double timeoutmax = (double) LONG_MAX + 0.999999; #endif if (d > timeoutmax) { diff --git a/main/network.c b/main/network.c index d4938a4a08c1e..df42f57358655 100644 --- a/main/network.c +++ b/main/network.c @@ -319,6 +319,14 @@ static inline void php_network_set_limit_time(struct timeval *limit_time, struct timeval *timeout) { gettimeofday(limit_time, NULL); +# ifdef PHP_WIN32 + /* cap timeout (we're not picky regarding usec) */ + if (limit_time->tv_sec > (LONG_MAX - timeout->tv_sec) + 1) { + limit_time->tv_sec = LONG_MAX; + limit_time->tv_usec = 999999; + return; + } +# endif limit_time->tv_sec += timeout->tv_sec; limit_time->tv_usec += timeout->tv_usec; if (limit_time->tv_usec >= 1000000) {