Skip to content

Commit caec2b6

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
2 parents 8edd621 + c087398 commit caec2b6

File tree

4 files changed

+68
-17
lines changed

4 files changed

+68
-17
lines changed

NEWS

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,18 @@ PHP NEWS
22
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
33
?? ??? ????, PHP 8.3.6
44

5+
- FPM:
6+
. Fixed bug GH-13563 (Setting bool values via env in FPM config fails).
7+
(Jakub Zelenka)
8+
59
- Opcache:
610
. Fixed bug GH-13433 (Segmentation Fault in zend_class_init_statics when
711
using opcache.preload). (nielsdos)
812

13+
- Streams:
14+
. Fixed bug GH-13264 (Part 1 - Memory leak on stream filter failure).
15+
(Jakub Zelenka)
16+
917
28 Mar 2024, PHP 8.3.5RC1
1018

1119
- Core:
@@ -26,8 +34,6 @@ PHP NEWS
2634
. Fixed GH-11086 (FPM: config test runs twice in daemonised mode).
2735
(Jakub Zelenka)
2836
. Fixed incorrect check in fpm_shm_free(). (nielsdos)
29-
. Fixed bug GH-13563 (Setting bool values via env in FPM config fails).
30-
(Jakub Zelenka)
3137

3238
- GD:
3339
. Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky)
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
--TEST--
2+
GH-81475: Memory leak during stream filter failure
3+
--SKIPIF--
4+
<?php require 'filter_errors.inc'; filter_errors_skipif('zlib.inflate'); ?>
5+
--FILE--
6+
<?php
7+
// Prepare a big enough input so that it is not entirely buffered
8+
$stream = fopen('php://memory', 'r+');
9+
$content = '';
10+
for ($i = 0; $i < 10000; $i++) {
11+
$content .= "Hello $i\n";
12+
}
13+
fwrite($stream, gzcompress($content));
14+
15+
// Mess up the checksum
16+
fseek($stream, -1, SEEK_CUR);
17+
fwrite($stream, '1');
18+
19+
// Rewind and add the zlib filter
20+
rewind($stream);
21+
stream_filter_append($stream, 'zlib.inflate', STREAM_FILTER_READ, ['window' => 15]);
22+
23+
// Read the filtered stream line by line.
24+
while (($line = fgets($stream)) !== false) {
25+
$error = error_get_last();
26+
if ($error !== null) {
27+
// An error is thrown but fgets didn't return false
28+
var_dump(error_get_last());
29+
var_dump($line);
30+
}
31+
}
32+
33+
fclose($stream);
34+
?>
35+
--EXPECTF--
36+
37+
Notice: fgets(): zlib: data error in %s on line %d
38+
array(4) {
39+
["type"]=>
40+
int(8)
41+
["message"]=>
42+
string(25) "fgets(): zlib: data error"
43+
["file"]=>
44+
string(%d) "%s"
45+
["line"]=>
46+
int(%d)
47+
}
48+
string(7) "Hello 6"
49+

ext/standard/user_filters.c

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -190,22 +190,7 @@ php_stream_filter_status_t userfilter_filter(
190190
}
191191

192192
if (buckets_in->head) {
193-
php_stream_bucket *bucket;
194-
195193
php_error_docref(NULL, E_WARNING, "Unprocessed filter buckets remaining on input brigade");
196-
while ((bucket = buckets_in->head)) {
197-
/* Remove unconsumed buckets from the brigade */
198-
php_stream_bucket_unlink(bucket);
199-
php_stream_bucket_delref(bucket);
200-
}
201-
}
202-
if (ret != PSFS_PASS_ON) {
203-
php_stream_bucket *bucket = buckets_out->head;
204-
while (bucket != NULL) {
205-
php_stream_bucket_unlink(bucket);
206-
php_stream_bucket_delref(bucket);
207-
bucket = buckets_out->head;
208-
}
209194
}
210195

211196
/* filter resources are cleaned up by the stream destructor,

main/streams/streams.c

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -636,6 +636,17 @@ PHPAPI zend_result _php_stream_fill_read_buffer(php_stream *stream, size_t size)
636636
/* some fatal error. Theoretically, the stream is borked, so all
637637
* further reads should fail. */
638638
stream->eof = 1;
639+
/* free all data left in brigades */
640+
while ((bucket = brig_inp->head)) {
641+
/* Remove unconsumed buckets from the input brigade */
642+
php_stream_bucket_unlink(bucket);
643+
php_stream_bucket_delref(bucket);
644+
}
645+
while ((bucket = brig_outp->head)) {
646+
/* Remove unconsumed buckets from the output brigade */
647+
php_stream_bucket_unlink(bucket);
648+
php_stream_bucket_delref(bucket);
649+
}
639650
efree(chunk_buf);
640651
retval = FAILURE;
641652
goto out_is_eof;

0 commit comments

Comments
 (0)