Bug #72561 [Ver]: 5.2.2 regressed with incorrect seeking in stream wrappers

From: Date: Sun, 11 Jun 2023 14:06:14 +0000
Subject: Bug #72561 [Ver]: 5.2.2 regressed with incorrect seeking in stream wrappers
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-244657@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=72561&edit=1 ID: 72561 Updated by: bukka@php.net Reported by: nazar at mokrynskyi dot com Summary: 5.2.2 regressed with incorrect seeking in stream wrappers Status: Verified Type: Bug Package: Streams related Operating System: Linux PHP Version: 7.1.0alpha1 -Assigned To: +Assigned To: bukka Block user comment: N Private report: N New Comment: I just had a closer look into this. What's happening here is that for buffered stream the seeking is done without calling wrapper sync only in some cases. The problem is that SEEK_CUR can be handled reliably only without calling the wrapper. However if the requested position is negative (that's most likely because the buffer can be moved so everything before does not need to exist) or it's in the position behind the buffer size, then it needs to call the wrapper. Obviously the user wrapper cannot know the right position. Only internal wrappers can know that position so they can work fine. So we cannot modify the offset in seek cur based on the read position (like in the example) because only user wrappers might be using that and internals wrappers can use the right position. I think the only thing that could be potentially done is converting SEEK_CUR to SEEK_SET which means changing offset to (ftell() + offset). I will need to think about it more and do some further checking first though. What could be also useful is to have a way how to access the stream resource in the wrapper. Although the API for that might be a bit challenging so will leave that one for later (just making a note in my TODO list). Previous Comments: ------------------------------------------------------------------------ [2020-09-08 11:34:08] cmb@php.net I agree that this behavior is confusing at best, but it is documented. Stream reads are buffered by default, and fseek() does not call ::stream_seek() if the target position is already contained in the read buffer[1]. However, that behavior renders our streamwrapper example[2] moot, since it relies on an internal position property like the supplied reproduce scripts in this ticket. [1] <https://www.php.net/manual/en/streamwrapper.stream-seek.php#refsect1-streamwrapper.stream-seek-notes> [2] <https://www.php.net/manual/en/stream.streamwrapper.example-1.php> ------------------------------------------------------------------------ [2017-12-20 16:18:58] cmb@php.net Related To: Bug #75708 ------------------------------------------------------------------------ [2016-07-08 08:16:21] requinix@php.net There's some weird magic going on, alright. https://3v4l.org/0oYBR#v550 1. stream_read gets called with the full 8192, implying PHP is automatically buffering the stream. This could be intentional (probably is) and may simply be an issue of documentation, but as a developer I would prefer PHP didn't do that for me. And I'll bet that 99% of stream wrapper code out there expects the method to be called with the specific length instead of the maximum length. 2. stream_tell is not being called. At all. The docs say it should be called when using fseek(), and one would expect it to be called with ftell() but apparently that's not the case, however it looks like PHP is managing the pointer position all by itself. 3. read 3 seek -1 results in ftell()=3 when it should be =2. Then later the read 2 results in ftell()=5 (should be =4). Seems that the relative seek isn't updating the internal pointer? > I believe this should be fixed and backported to stable versions, So we're clear, that would be 5.6.x, 7.0.y, and 7.1.z. Because 5.5 is dead and there's no way any changes would get into versions earlier than that. ------------------------------------------------------------------------ [2016-07-08 01:33:35] nazar at mokrynskyi dot com Description: ------------ When doing reading/seeking on stream wrapper, PHP does interesting magic under the hood (for instance, reading 3 bytes results in 8192 bytes actually tried to be read in ::stream_read()). This is all fine until it works as expected. Here is demo: https://3v4l.org/3RG7r PHP 5.1.4 - 5.2.1 have expected correct output. hhvm-3.9.1 - 3.12.0 seems to also have optimizations under the hood, but result is correct anyway. PHP 5.2.2+ (including latest 7.1.0-alpha2) regressed and does incorrect seeking which results in wrong position eventually. I believe this should be fixed and backported to stable versions, since I do not see any good workaround here, input in ::stream_seek() is already incorrect. ------------------------------------------------------------------------ -- Edit this bug report at https://bugs.php.net/bug.php?id=72561&edit=1

« previous php.bugs (#244657) next »