diff --git a/NEWS b/NEWS index fc3c0662b9328..86e5ed60066fa 100644 --- a/NEWS +++ b/NEWS @@ -27,6 +27,10 @@ PHP NEWS of the curl_copy_handle() function to clone a CurlHandle. (timwolla) . Fix curl build failure on macOS+curl 8.16. (nielsdos) +- SPL: + . Fixed bug GH-19942 (iterator_count() on an empty SplFileObject looping + infinitely). (alexandre-daubois) + - Soap: . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 0a4d1456d65e9..f2f109d6e04f7 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2166,6 +2166,29 @@ PHP_METHOD(SplFileObject, valid) if (!intern->u.file.stream) { RETURN_FALSE; } + + /* For empty files, php_stream_eof() might not return TRUE until after a read attempt. + * If we're at the beginning and haven't read anything, check EOF directly after ensuring + * a read has been attempted (only on seekable streams). */ + if (!intern->u.file.current_line && Z_ISUNDEF(intern->u.file.current_zval) && + intern->u.file.current_line_num == 0) { + + if (intern->u.file.stream->ops->seek && + (intern->u.file.stream->flags & PHP_STREAM_FLAG_NO_SEEK) == 0) { + + if (php_stream_eof(intern->u.file.stream)) { + RETURN_FALSE; + } + + if (php_stream_tell(intern->u.file.stream) == 0) { + php_stream_statbuf ssb; + if (php_stream_stat(intern->u.file.stream, &ssb) == 0 && ssb.sb.st_size == 0) { + RETURN_FALSE; + } + } + } + } + RETURN_BOOL(!php_stream_eof(intern->u.file.stream)); } /* }}} */ diff --git a/ext/spl/tests/SplFileObject_iterator_count_empty_file.phpt b/ext/spl/tests/SplFileObject_iterator_count_empty_file.phpt new file mode 100644 index 0000000000000..40d1a189bc91c --- /dev/null +++ b/ext/spl/tests/SplFileObject_iterator_count_empty_file.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-19942 (iterator_count() on an empty SplFileObject should return 0) +--FILE-- + +--EXPECT-- +int(0) diff --git a/ext/spl/tests/SplFileObject_non_seekable_stream.phpt b/ext/spl/tests/SplFileObject_non_seekable_stream.phpt new file mode 100644 index 0000000000000..2c8d039360a09 --- /dev/null +++ b/ext/spl/tests/SplFileObject_non_seekable_stream.phpt @@ -0,0 +1,11 @@ +--TEST-- +SplFileObject::valid() with non-seekable streams should not hang +--FILE-- +valid()); +?> +--STDIN-- + +--EXPECT-- +bool(true)