Skip to content

Fix read buffer compaction in stream filter flush - #23439

Closed
crystarm wants to merge 1 commit into
php:PHP-8.4from
crystarm:fix/stream-filter-flush-buffer-compaction
Closed

Fix read buffer compaction in stream filter flush#23439
crystarm wants to merge 1 commit into
php:PHP-8.4from
crystarm:fix/stream-filter-flush-buffer-compaction

Conversation

@crystarm

Copy link
Copy Markdown
Contributor

php_stream_filter_flush() compacts unread data before appending buckets produced by a read filter.

The source and destination ranges may overlap, making the use of memcpy() undefined behavior. Additionally, readpos was reset before it was subtracted from writepos, so the buffer size was not adjusted and stale data could remain visible.

Use memmove() and adjust writepos before resetting readpos, matching the existing buffer compaction logic in php_stream_fill_read_buffer().

The issue was detected by static analysis: BUFFER_OVERLAP filter.c:[458:4].log

@crystarm
crystarm requested a review from bukka as a code owner August 24, 2026 15:23
@crystarm

Copy link
Copy Markdown
Contributor Author

Small clarification: the allocated buffer size (readbuflen) was not affected. Rather, resetting readpos before the subtraction left writepos unchanged, which could expose stale or duplicate bytes from the read buffer.

@LamentXU123 LamentXU123 left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add this test please?

--TEST--
stream_filter_remove() compacts unread data before appending flushed data
--FILE--
<?php
class ClosingSuffixFilter extends php_user_filter
{
    public function filter($in, $out, &$consumed, $closing): int
    {
        while ($bucket = stream_bucket_make_writeable($in)) {
            $consumed += $bucket->datalen;
            stream_bucket_append($out, $bucket);
        }
        if ($closing) {
            stream_bucket_append($out, stream_bucket_new($this->stream, 'END'));
        }
        return PSFS_PASS_ON;
    }
}
stream_filter_register('closing-suffix', ClosingSuffixFilter::class);
$stream = fopen('php://memory', 'w+');
fwrite($stream, 'abcdef');
rewind($stream);
$filter = stream_filter_append($stream, 'closing-suffix', STREAM_FILTER_READ);
var_dump(fread($stream, 2));
var_dump(stream_filter_remove($filter));
var_dump(stream_get_contents($stream));
?>
--EXPECT--
string(2) "ab"
bool(true)
string(7) "cdefEND"

Also, could you please rebase to 8.4 instead of master?

@crystarm
crystarm force-pushed the fix/stream-filter-flush-buffer-compaction branch from 63313ad to 4a3a0bb Compare August 26, 2026 13:33
@crystarm
crystarm changed the base branch from master to PHP-8.4 August 26, 2026 13:34
@crystarm

Copy link
Copy Markdown
Contributor Author

@LamentXU123
Addresed!! ദ്ദി(˵ •̀ ᴗ - ˵ ) ✧

@LamentXU123
LamentXU123 requested a review from devnexen August 26, 2026 13:37
@crystarm

Copy link
Copy Markdown
Contributor Author

@LamentXU123
Maybe I should also rebase this PR onto 8.4?

@LamentXU123

Copy link
Copy Markdown
Member

Not sure. The phar one is controversial and we should wait for other's agreement :) I think people will look back to it before the hard feature freeze.

LamentXU123 added a commit that referenced this pull request Aug 27, 2026
* PHP-8.5:
  Fix read buffer compaction in stream filter flush (#23439)
@LamentXU123

LamentXU123 commented Aug 27, 2026

Copy link
Copy Markdown
Member

@crystarm Thank you so much! Note that I added a NEWS entry for you so what I merged is different to what you've wrote here.

pull Bot pushed a commit to wudi/php-src that referenced this pull request Aug 27, 2026
* PHP-8.4:
  Fix read buffer compaction in stream filter flush (php#23439)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants