[php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6

From: Date: Mon, 05 Oct 2026 09:38:21 +0000
Subject: [php-src] PHP-8.6: Merge branch 'PHP-8.5' into PHP-8.6
Groups: php.cvs 
Request: Send a blank email to php-cvs+get-141952@lists.php.net to get a copy of this message
Author: Jakub Zelenka (bukka) Date: 2026-10-05T11:38:10+02:00 Commit: https://github.com/php/php-src/commit/e91a8435995edb72661e0e9bf5c82c544c8889c6 Raw diff: https://github.com/php/php-src/commit/e91a8435995edb72661e0e9bf5c82c544c8889c6.diff Merge branch 'PHP-8.5' into PHP-8.6 * PHP-8.5: Fix TLS stream EOF detection after close_notify with stale errno (#24132) Changed paths: A ext/openssl/tests/stream_eof_after_close_notify.phpt M NEWS M ext/openssl/xp_ssl.c Diff: diff --git a/NEWS b/NEWS index b94fc6ba52b1..bc63b84709c2 100644 --- a/NEWS +++ b/NEWS @@ -76,6 +76,8 @@ PHP NEWS . Fix memory leak by doing early salt validation. (adapik) . Fixed openssl_sign() using the maximum RSA-PSS salt length by default instead of the OpenSSL default. (adapik) + . Fixed feof() on a TLS stream staying false after a close_notify on Windows. + (Jakub Zelenka) - PCNTL: . Fixed pcntl_signal_dispatch() dropping the queued signals when it runs while diff --git a/ext/openssl/tests/stream_eof_after_close_notify.phpt b/ext/openssl/tests/stream_eof_after_close_notify.phpt new file mode 100644 index 000000000000..4755e171544d --- /dev/null +++ b/ext/openssl/tests/stream_eof_after_close_notify.phpt @@ -0,0 +1,58 @@ +--TEST-- +feof() is true after a TLS close_notify even if an earlier read left errno set to EAGAIN +--EXTENSIONS-- +openssl +--SKIPIF-- +<?php +if (!function_exists("proc_open")) die("skip no proc_open"); +?> +--FILE-- +<?php +$certFile = __DIR__ . DIRECTORY_SEPARATOR . 'stream_eof_after_close_notify.pem.tmp'; + +$serverCode = <<<'CODE' + $serverCtx = stream_context_create(['ssl' => ['local_cert' => '%s']]); + $sock = stream_socket_server("tls://127.0.0.1:0", $errno, $errstr, + STREAM_SERVER_BIND | STREAM_SERVER_LISTEN, $serverCtx); + phpt_notify_server_start($sock); + + $link = stream_socket_accept($sock); + /* Let the client block in fread() first, so its SSL_read() sees WANT_READ */ + phpt_wait(); + usleep(100000); + fwrite($link, "data"); + /* close_notify only, the TCP connection stays open */ + stream_socket_enable_crypto($link, false); + phpt_wait(); + fclose($link); +CODE; +$serverCode = sprintf($serverCode, $certFile); + +$clientCode = <<<'CODE' + $clientCtx = stream_context_create(['ssl' => [ + 'verify_peer' => false, + 'verify_peer_name' => false, + ]]); + $sock = stream_socket_client("tls://{{ ADDR }}", $errno, $errstr, 2, STREAM_CLIENT_CONNECT, $clientCtx); + + phpt_notify(); + var_dump(fread($sock, 4)); + var_dump(fread($sock, 4)); + var_dump(feof($sock)); + phpt_notify(); +CODE; + +include 'CertificateGenerator.inc'; +(new CertificateGenerator())->saveNewCertAsFileWithKey('stream_eof_after_close_notify', $certFile); + +include 'ServerClientTestCase.inc'; +ServerClientTestCase::getInstance()->run($clientCode, $serverCode); +?> +--CLEAN-- +<?php +@unlink(__DIR__ . DIRECTORY_SEPARATOR . 'stream_eof_after_close_notify.pem.tmp'); +?> +--EXPECT-- +string(4) "data" +string(0) "" +bool(true) diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index cf3793fd5514..ad06af444ffe 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -3243,9 +3243,11 @@ static ssize_t php_openssl_sockop_io(int read, php_stream *stream, char *buf, si retry = 1; } - /* Also, on reads, we may get this condition on an EOF. We should check properly. */ if (read) { - stream->eof = (retry == 0 && errno != EAGAIN && !SSL_pending(sslsock->ssl_handle)); + /* EOF unless the SSL layer just needs to wait. */ + stream->eof = (retry == 0 + && err != SSL_ERROR_WANT_READ && err != SSL_ERROR_WANT_WRITE + && !SSL_pending(sslsock->ssl_handle)); } /* Don't loop indefinitely in non-blocking mode if no data is available */

« previous php.cvs (#141952) next »