Repository navigation
Fix GH-25232: ftruncate() does not invalidate stat cache #25233
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: PHP-8.4
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| --TEST-- | ||
| GH-25232: ftruncate() does not invalidate stat cache | ||
| --FILE-- | ||
| <?php | ||
| $file = __DIR__ . '/gh25232.tmp'; | ||
| file_put_contents($file, 'abcdefgh'); | ||
| $handle = fopen($file, 'r+'); | ||
|
|
||
| var_dump(filesize($file)); | ||
| var_dump(ftruncate($handle, 3)); | ||
| var_dump(filesize($file)); | ||
|
|
||
| fclose($handle); | ||
|
|
||
| $obj = new SplFileObject($file, 'r+'); | ||
| var_dump(filesize($file)); | ||
| var_dump($obj->ftruncate(1)); | ||
| var_dump(filesize($file)); | ||
| ?> | ||
| --CLEAN-- | ||
| <?php | ||
| @unlink(__DIR__ . '/gh25232.tmp'); | ||
| ?> | ||
| --EXPECT-- | ||
| int(8) | ||
| bool(true) | ||
| int(3) | ||
| int(3) | ||
| bool(true) | ||
| int(1) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -1018,10 +1018,16 @@ static int php_stdiop_set_option(php_stream *stream, int option, int value, void | |
| if (!SetFilePointerEx(h, old_sz, NULL, FILE_BEGIN)) { | ||
| return PHP_STREAM_OPTION_RETURN_ERR; | ||
| } | ||
| return PHP_STREAM_OPTION_RETURN_OK; | ||
| #else | ||
| return ftruncate(fd, new_size) == 0 ? PHP_STREAM_OPTION_RETURN_OK : PHP_STREAM_OPTION_RETURN_ERR; | ||
| if (ftruncate(fd, new_size) != 0) { | ||
| return PHP_STREAM_OPTION_RETURN_ERR; | ||
| } | ||
| #endif | ||
| if (EG(active)) { | ||
| /* clear stat cache as size, mtime and ctime got changed */ | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clearing the global stat cache here fixes Unlike $f = tempnam(sys_get_temp_dir(), 'trunc_');
file_put_contents($f, str_repeat('A', 100));
$h = fopen($f, 'r+');
fread($h, 10); // stream pre-buffers 8KB into stream->readbuf
ftruncate($h, 10); // truncated to 10 bytes on disk
var_dump(filesize($f)); // int(10)
var_dump(fread($h, 50)); // returns 50 bytes of stale buffer past EOF
fclose($h);
unlink($f);Should stream buffer invalidation be handled in
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to keep this PR to the stat cache. The stale read buffer is real, but stock 8.4.27 shows the same output, so it is a separate bug and should get its own issue and fix. |
||
| php_clear_stat_cache(0, NULL, 0); | ||
| } | ||
| return PHP_STREAM_OPTION_RETURN_OK; | ||
| } | ||
| } | ||
| return PHP_STREAM_OPTION_RETURN_NOTIMPL; | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Writing directly to
__DIR__breaks out-of-tree builds where the source tree is mounted read-only (e.g. CI packaging setups or--srcdirtesting). If the test crashes or aborts before reaching--CLEAN--, it also leaves untracked temporary files in the worktree.Using
tempnam(sys_get_temp_dir(), ...)(as in the original GH-25232 issue report) would be safer and keep the source tree clean.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I kept
__DIR__because most tests in ext/standard/tests/file write there and clean up in--CLEAN--. For a read-only source tree, run-tests has--temp-sourceand--temp-target.