diff --git a/NEWS b/NEWS index 361a896d8d0..55367865c24 100644 --- a/NEWS +++ b/NEWS @@ -2,10 +2,18 @@ PHP NEWS ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||| ?? ??? ????, PHP 8.3.6 +- FPM: + . Fixed bug GH-13563 (Setting bool values via env in FPM config fails). + (Jakub Zelenka) + - Opcache: . Fixed bug GH-13433 (Segmentation Fault in zend_class_init_statics when using opcache.preload). (nielsdos) +- Streams: + . Fixed bug GH-13264 (Part 1 - Memory leak on stream filter failure). + (Jakub Zelenka) + 28 Mar 2024, PHP 8.3.5RC1 - Core: @@ -26,8 +34,6 @@ PHP NEWS . Fixed GH-11086 (FPM: config test runs twice in daemonised mode). (Jakub Zelenka) . 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) 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 adfec58e8db..063895e2f40 100644 --- a/ext/standard/user_filters.c +++ b/ext/standard/user_filters.c @@ -190,22 +190,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 9f79821f0c9..65ec69bffce 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -636,6 +636,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); retval = FAILURE; goto out_is_eof;