From cd6a58114e9649495d3a4a8c3f628a7473f6c880 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Fri, 29 Mar 2024 16:05:13 +0000 Subject: [PATCH 1/2] Fix NEWS for the last FPM change --- NEWS | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/NEWS b/NEWS index 86dccc9a06d..3517d0eeb08 100644 --- a/NEWS +++ b/NEWS @@ -2,6 +2,9 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.2.19 +- FPM: + . Fixed bug GH-13563 (Setting bool values via env in FPM config fails). + (Jakub Zelenka) 11 Apr 2024, PHP 8.2.18 @@ -19,8 +22,6 @@ PHP NEWS - FPM . Fixed incorrect check in fpm_shm_free(). (nielsdos) - . Fixed bug GH-13563 (Setting bool values via env in FPM config fails). - (Jakub Zelenka) - GD: . Fixed bug GH-12019 (add GDLIB_CFLAGS in feature tests). (Michael Orlitzky) From c087398cc2efb437213cba603e98c82fc9cd88ac Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Sat, 23 Mar 2024 13:09:46 +0000 Subject: [PATCH 2/2] Fix GH-13264: Part 1 - Memory leak on filter failure Closes GH-13790 --- NEWS | 4 ++ ext/standard/tests/filters/gh13264.phpt | 49 +++++++++++++++++++++++++ ext/standard/user_filters.c | 15 -------- main/streams/streams.c | 11 ++++++ 4 files changed, 64 insertions(+), 15 deletions(-) create mode 100644 ext/standard/tests/filters/gh13264.phpt diff --git a/NEWS b/NEWS index 3517d0eeb08..b3a9c4963ff 100644 --- a/NEWS +++ b/NEWS @@ -6,6 +6,10 @@ PHP NEWS . Fixed bug GH-13563 (Setting bool values via env in FPM config fails). (Jakub Zelenka) +- Streams: + . Fixed bug GH-13264 (Part 1 - Memory leak on stream filter failure). + (Jakub Zelenka) + 11 Apr 2024, PHP 8.2.18 - Core: diff --git a/ext/standard/tests/filters/gh13264.phpt b/ext/standard/tests/filters/gh13264.phpt new file mode 100644 index 00000000000..6456a082a1e --- /dev/null +++ b/ext/standard/tests/filters/gh13264.phpt @@ -0,0 +1,49 @@ +--TEST-- +GH-81475: Memory leak during stream filter failure +--SKIPIF-- + +--FILE-- + 15]); + +// Read the filtered stream line by line. +while (($line = fgets($stream)) !== false) { + $error = error_get_last(); + if ($error !== null) { + // An error is thrown but fgets didn't return false + var_dump(error_get_last()); + var_dump($line); + } +} + +fclose($stream); +?> +--EXPECTF-- + +Notice: fgets(): zlib: data error in %s on line %d +array(4) { + ["type"]=> + int(8) + ["message"]=> + string(25) "fgets(): zlib: data error" + ["file"]=> + string(%d) "%s" + ["line"]=> + int(%d) +} +string(7) "Hello 6" + diff --git a/ext/standard/user_filters.c b/ext/standard/user_filters.c index dcbfc381d29..8995471af45 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -196,22 +196,7 @@ php_stream_filter_status_t userfilter_filter( } if (buckets_in->head) { - php_stream_bucket *bucket; - php_error_docref(NULL, E_WARNING, "Unprocessed filter buckets remaining on input brigade"); - while ((bucket = buckets_in->head)) { - /* Remove unconsumed buckets from the brigade */ - php_stream_bucket_unlink(bucket); - php_stream_bucket_delref(bucket); - } - } - if (ret != PSFS_PASS_ON) { - php_stream_bucket *bucket = buckets_out->head; - while (bucket != NULL) { - php_stream_bucket_unlink(bucket); - php_stream_bucket_delref(bucket); - bucket = buckets_out->head; - } } /* filter resources are cleaned up by the stream destructor, diff --git a/main/streams/streams.c b/main/streams/streams.c index d45a9bfab85..33f8b7e7a80 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -632,6 +632,17 @@ PHPAPI zend_result _php_stream_fill_read_buffer(php_stream *stream, size_t size) /* some fatal error. Theoretically, the stream is borked, so all * further reads should fail. */ stream->eof = 1; + /* free all data left in brigades */ + while ((bucket = brig_inp->head)) { + /* Remove unconsumed buckets from the input brigade */ + php_stream_bucket_unlink(bucket); + php_stream_bucket_delref(bucket); + } + while ((bucket = brig_outp->head)) { + /* Remove unconsumed buckets from the output brigade */ + php_stream_bucket_unlink(bucket); + php_stream_bucket_delref(bucket); + } efree(chunk_buf); return FAILURE; }