From 660ef91fbc359b31aa897e04b5e2d7b75e0c1633 Mon Sep 17 00:00:00 2001 From: George Peter Banyard Date: Thu, 7 Apr 2022 14:24:04 +0100 Subject: [PATCH] Fix GH-8273: SplFileObject: key() returns wrong value --- NEWS | 1 + ext/spl/spl_directory.c | 17 +++++--- .../SplFileObject_key_fgets_and seek.phpt | 39 +++++++++++++++++++ ext/spl/tests/gh8273.phpt | 24 ++++++++++++ 4 files changed, 75 insertions(+), 6 deletions(-) create mode 100644 ext/spl/tests/SplFileObject_key_fgets_and seek.phpt create mode 100644 ext/spl/tests/gh8273.phpt diff --git a/NEWS b/NEWS index 048fdfea12f..7f10a49abfb 100644 --- a/NEWS +++ b/NEWS @@ -36,6 +36,7 @@ PHP NEWS - SPL: . Fixed bug GH-8366 (ArrayIterator may leak when calling __construct()). (cmb) + . Fixed bug GH-8273 (SplFileObject: key() returns wrong value). (Girgias) - Streams: . Fixed php://temp does not preserve file-position when switched to temporary diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c index 9b4509461af..4edc6361605 100644 --- a/ext/spl/spl_directory.c +++ b/ext/spl/spl_directory.c @@ -1864,11 +1864,10 @@ static int spl_filesystem_object_cast(zend_object *readobj, zval *writeobj, int } /* }}} */ -static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent) /* {{{ */ +static zend_result spl_filesystem_file_read_ex(spl_filesystem_object *intern, bool silent, zend_long line_add) /* {{{ */ { char *buf; size_t line_len = 0; - zend_long line_add = (intern->u.file.current_line || !Z_ISUNDEF(intern->u.file.current_zval)) ? 1 : 0; spl_filesystem_file_free_line(intern); @@ -1913,7 +1912,13 @@ static int spl_filesystem_file_read(spl_filesystem_object *intern, int silent) / return SUCCESS; } /* }}} */ -static int spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value) /* {{{ */ +static inline zend_result spl_filesystem_file_read(spl_filesystem_object *intern, bool silent) +{ + zend_long line_add = (intern->u.file.current_line) ? 1 : 0; + return spl_filesystem_file_read_ex(intern, silent, line_add); +} + +static zend_result spl_filesystem_file_read_csv(spl_filesystem_object *intern, char delimiter, char enclosure, int escape, zval *return_value) /* {{{ */ { do { int ret = spl_filesystem_file_read(intern, 1); @@ -2176,7 +2181,7 @@ PHP_METHOD(SplFileObject, fgets) CHECK_SPL_FILE_OBJECT_IS_INITIALIZED(intern); - if (spl_filesystem_file_read(intern, 0) == FAILURE) { + if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1) == FAILURE) { RETURN_THROWS(); } RETURN_STRINGL(intern->u.file.current_line, intern->u.file.current_line_len); @@ -2214,8 +2219,8 @@ PHP_METHOD(SplFileObject, key) RETURN_THROWS(); } -/* Do not read the next line to support correct counting with fgetc() - if (!intern->current_line) { + /* Do not read the next line to support correct counting with fgetc() + if (!intern->u.file.current_line) { spl_filesystem_file_read_line(ZEND_THIS, intern, 1); } */ RETURN_LONG(intern->u.file.current_line_num); diff --git a/ext/spl/tests/SplFileObject_key_fgets_and seek.phpt b/ext/spl/tests/SplFileObject_key_fgets_and seek.phpt new file mode 100644 index 00000000000..eef6c37745d --- /dev/null +++ b/ext/spl/tests/SplFileObject_key_fgets_and seek.phpt @@ -0,0 +1,39 @@ +--TEST-- +SplFileObject verify interactions between seeking, getting the key and fgets +--FILE-- +fwrite("Foo $i\n"); +} + +$file->seek(50); + +var_dump( + ['line' => $file->key(), 'contents' => trim($file->fgets())], + ['line' => $file->key(), 'contents' => trim($file->fgets())], + ['line' => $file->key(), 'contents' => trim($file->fgets())], +); + +?> +--EXPECT-- +array(2) { + ["line"]=> + int(50) + ["contents"]=> + string(6) "Foo 50" +} +array(2) { + ["line"]=> + int(51) + ["contents"]=> + string(6) "Foo 51" +} +array(2) { + ["line"]=> + int(52) + ["contents"]=> + string(6) "Foo 52" +} diff --git a/ext/spl/tests/gh8273.phpt b/ext/spl/tests/gh8273.phpt new file mode 100644 index 00000000000..87931541653 --- /dev/null +++ b/ext/spl/tests/gh8273.phpt @@ -0,0 +1,24 @@ +--TEST-- +GH-8273 (SplFileObject: key() returns wrong value) +--FILE-- +fwrite("line {$i}" . PHP_EOL); +} + +// read from file +$file->rewind(); +while ($file->valid()) { + echo $file->key(), ': ', $file->fgets(); +} +?> +--EXPECT-- +0: line 0 +1: line 1 +2: line 2 +3: line 3 +4: line 4