Skip to content

Commit 6035b0a

Browse files
committed
Fix GH-8561: SplFileObject key()/current() desync after fgets()
fgets() read a line into the cache and incremented the line counter, but left the cached line in place. The subsequent current() returned the stale cached value instead of reading the next line from the stream's actual position. Clear the cached line after fgets() copies it to the return value. This forces current() to re-read from the stream, which has already advanced past the fgets'd line. Closes GH-8561
1 parent c4c3bed commit 6035b0a

File tree

2 files changed

+32
-1
lines changed

2 files changed

+32
-1
lines changed

ext/spl/spl_directory.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2096,7 +2096,8 @@ PHP_METHOD(SplFileObject, fgets)
20962096
if (spl_filesystem_file_read_ex(intern, /* silent */ false, /* line_add */ 1, /* csv */ false) == FAILURE) {
20972097
RETURN_THROWS();
20982098
}
2099-
RETURN_STR_COPY(intern->u.file.current_line);
2099+
RETVAL_STR_COPY(intern->u.file.current_line);
2100+
spl_filesystem_file_free_line(intern);
21002101
} /* }}} */
21012102

21022103
/* {{{ Return current line from file */
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
--TEST--
2+
GH-8561 (SplFileObject: key() and current() unsynchronized after fgets())
3+
--FILE--
4+
<?php
5+
$file = new SplTempFileObject();
6+
for ($i = 0; $i < 5; $i++) {
7+
$file->fwrite("line {$i}" . PHP_EOL);
8+
}
9+
10+
// Case 1: rewind + fgets, then key/current
11+
$file->rewind();
12+
$file->fgets();
13+
echo "After rewind+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n";
14+
15+
// Case 2: multiple fgets
16+
$file->rewind();
17+
$file->fgets();
18+
$file->fgets();
19+
echo "After rewind+fgets+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n";
20+
21+
// Case 3: current then fgets
22+
$file->rewind();
23+
$file->current();
24+
$file->fgets();
25+
echo "After current+fgets: key=" . $file->key() . " current=" . trim($file->current()) . "\n";
26+
?>
27+
--EXPECT--
28+
After rewind+fgets: key=1 current=line 1
29+
After rewind+fgets+fgets: key=2 current=line 2
30+
After current+fgets: key=1 current=line 2

0 commit comments

Comments
 (0)