diff --git a/NEWS b/NEWS index 4cdf09ba407..26f20f23e6b 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.6 +- Streams: + . Fixed bug GH-10406 (feof() behavior change for UNIX based socket + resources). (Jakub Zelenka) 30 Mar 2023, PHP 8.2.5 diff --git a/ext/openssl/xp_ssl.c b/ext/openssl/xp_ssl.c index 2ec25bee091..79dd0b4f9c7 100644 --- a/ext/openssl/xp_ssl.c +++ b/ext/openssl/xp_ssl.c @@ -2429,8 +2429,15 @@ static int php_openssl_sockop_set_option(php_stream *stream, int option, int val if (sslsock->s.socket == -1) { alive = 0; - } else if ((!sslsock->ssl_active && value == 0 && ((MSG_DONTWAIT != 0) || !sslsock->s.is_blocked)) || - php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { + } else if ( + ( + !sslsock->ssl_active && + value == 0 && + !(stream->flags & PHP_STREAM_FLAG_NO_IO) && + ((MSG_DONTWAIT != 0) || !sslsock->s.is_blocked) + ) || + php_pollfd_for(sslsock->s.socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0 + ) { /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */ /* additionally, we don't use this optimization if SSL is active because in that case, we're not using MSG_DONTWAIT */ if (sslsock->ssl_active) { diff --git a/ext/standard/tests/streams/gh10406.phpt b/ext/standard/tests/streams/gh10406.phpt new file mode 100644 index 00000000000..0721dfbe9ed --- /dev/null +++ b/ext/standard/tests/streams/gh10406.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10406: feof() behavior change for UNIX based socket resources +--SKIPIF-- + +--FILE-- + +--EXPECT-- +bool(false) diff --git a/main/php_streams.h b/main/php_streams.h index 71ef26c9701..e7cbc7369ed 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -188,6 +188,8 @@ struct _php_stream_wrapper { /* Do not close handle except it is explicitly closed by user (e.g. fclose) */ #define PHP_STREAM_FLAG_NO_RSCR_DTOR_CLOSE 0x200 +#define PHP_STREAM_FLAG_NO_IO 0x400 + #define PHP_STREAM_FLAG_WAS_WRITTEN 0x80000000 struct _php_stream { diff --git a/main/streams/transports.c b/main/streams/transports.c index 35ac4ae27ad..6fc2848be6e 100644 --- a/main/streams/transports.c +++ b/main/streams/transports.c @@ -169,6 +169,9 @@ PHPAPI php_stream *_php_stream_xport_create(const char *name, size_t namelen, in failed = true; } } + if (!failed) { + stream->flags |= PHP_STREAM_FLAG_NO_IO; + } } } } zend_catch { diff --git a/main/streams/xp_socket.c b/main/streams/xp_socket.c index be41d3dde78..3ba79df6349 100644 --- a/main/streams/xp_socket.c +++ b/main/streams/xp_socket.c @@ -337,7 +337,14 @@ static int php_sockop_set_option(php_stream *stream, int option, int value, void if (sock->socket == -1) { alive = 0; - } else if ((value == 0 && ((MSG_DONTWAIT != 0) || !sock->is_blocked)) || php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0) { + } else if ( + ( + value == 0 && + !(stream->flags & PHP_STREAM_FLAG_NO_IO) && + ((MSG_DONTWAIT != 0) || !sock->is_blocked) + ) || + php_pollfd_for(sock->socket, PHP_POLLREADABLE|POLLPRI, &tv) > 0 + ) { /* the poll() call was skipped if the socket is non-blocking (or MSG_DONTWAIT is available) and if the timeout is zero */ #ifdef PHP_WIN32 int ret;