[php-src] master: Merge branch 'PHP-8.4' into PHP-8.5

Weilin Du <[email protected]>
Newsgroups gmane.comp.php.cvs.general
Message-ID <[email protected]>
Author: Weilin Du (LamentXU123)
Date: 2026-08-28T00:52:49+08:00

Commit: https://github.com/php/php-src/commit/1a4a22fb1e86433616c91ad78bc82df82d4e55ad
Raw diff: https://github.com/php/php-src/commit/1a4a22fb1e86433616c91ad78bc82df82d4e55ad.diff

Merge branch 'PHP-8.4' into PHP-8.5

* PHP-8.4:
  Fix read buffer compaction in stream filter flush (#23439)

Changed paths:
  A  ext/standard/tests/filters/stream_filter_remove_compact_read_buffer.phpt
  M  NEWS
  M  main/streams/filter.c


Diff:

diff --git a/NEWS b/NEWS
index 074990dc4d57..7ca307951407 100644
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,7 @@ PHP                                                                        NEWS
 - Standard:
   . Fixed an out-of-bounds read when following a redirect response with an
     empty Location header. (iliaal)
+  . Fixed read buffer compaction in php_stream_filter_flush(). (crystarm)
 
 - Zip:
   . Fixed bug GH-17787 (ZipArchive stream stops reading early when the archive
diff --git a/ext/standard/tests/filters/stream_filter_remove_compact_read_buffer.phpt b/ext/standard/tests/filters/stream_filter_remove_compact_read_buffer.phpt
new file mode 100644
index 000000000000..7cfef971e7e7
--- /dev/null
+++ b/ext/standard/tests/filters/stream_filter_remove_compact_read_buffer.phpt
@@ -0,0 +1,31 @@
+--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"
diff --git a/main/streams/filter.c b/main/streams/filter.c
index d0c1fdc8e788..bf856f0c1e6e 100644
--- a/main/streams/filter.c
+++ b/main/streams/filter.c
@@ -455,9 +455,9 @@ PHPAPI zend_result _php_stream_filter_flush(php_stream_filter *filter, bool fini
 		/* Dump any newly flushed data to the read buffer */
 		if (stream->readpos > 0) {
 			/* Back the buffer up */
-			memcpy(stream->readbuf, stream->readbuf + stream->readpos, stream->writepos - stream->readpos);
-			stream->readpos = 0;
+			memmove(stream->readbuf, stream->readbuf + stream->readpos, stream->writepos - stream->readpos);
 			stream->writepos -= stream->readpos;
+			stream->readpos = 0;
 		}
 		if (flushed_size > (stream->readbuflen - stream->writepos)) {
 			/* Grow the buffer */
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.