diff --git a/NEWS b/NEWS index b2b8aaacf1520..f2961323a08f7 100644 --- a/NEWS +++ b/NEWS @@ -57,6 +57,10 @@ PHP NEWS . Fixed bug GH-19988 (zend_string_init with NULL pointer in simplexml (UB)). (nielsdos) +- SPL: + . Fixed bug GH-19942 (iterator_count() on an SplFileObject looping + infinitely). (alexandre-daubois) + - Soap: . Fixed bug GH-19784 (SoapServer memory leak). (nielsdos) . Fixed bug GH-20011 (Array of SoapVar of unknown type causes crash). diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 0a4d1456d65e9..e714c10ce93d0 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -2235,9 +2235,17 @@ PHP_METHOD(SplFileObject, next) RETURN_THROWS(); } + bool had_current_line = (intern->u.file.current_line != NULL || !Z_ISUNDEF(intern->u.file.current_zval)); spl_filesystem_file_free_line(intern); if (SPL_HAS_FLAG(intern->flags, SPL_FILE_OBJECT_READ_AHEAD)) { spl_filesystem_file_read_line(ZEND_THIS, intern, true); + } else if (!had_current_line) { + /* If there was no current line before, we need to advance the stream position + * for iterator_count() and other iterator operations to work correctly. + * Read and immediately discard a line. */ + if (spl_filesystem_file_read_line(ZEND_THIS, intern, true) == SUCCESS) { + spl_filesystem_file_free_line(intern); + } } intern->u.file.current_line_num++; } /* }}} */ 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..ac9075c8c7527 --- /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(1) diff --git a/ext/spl/tests/SplFileObject_iterator_count_non_empty_file.phpt b/ext/spl/tests/SplFileObject_iterator_count_non_empty_file.phpt new file mode 100644 index 0000000000000..3e6298c13e7c0 --- /dev/null +++ b/ext/spl/tests/SplFileObject_iterator_count_non_empty_file.phpt @@ -0,0 +1,16 @@ +--TEST-- +GH-19942 (iterator_count() on a non-empty SplFileObject should return correct count) +--FILE-- + +--EXPECT-- +int(3) 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)