[php-src] Issue #24508: HTTP wrapper leaks dechunk filter when header parsing fails after Transfer-Encoding: chunked
| From: | IzieStratt | Date: | Wed, 21 Oct 2026 20:39:10 +0000 |
| Subject: | [php-src] Issue #24508: HTTP wrapper leaks dechunk filter when header parsing fails after Transfer-Encoding: chunked | ||
| Groups: | php.bugs | ||
| Request: | Send a blank email to php-bugs+get-253065@lists.php.net to get a copy of this message | ||
Issue: https://github.com/php/php-src/issues/24508
Author: IzieStratt
### Description
The following code:
server.php (run first,
php server.php):
```php
<?php
$srv = stream_socket_server("tcp://127.0.0.1:18231", $errno, $errstr);
$conn = stream_socket_accept($srv);
while (($line = fgets($conn, 8192)) !== false) { if (trim($line) === '') break; }
// Transfer-Encoding: chunked, then a malformed header line
fwrite($conn, "HTTP/1.1 200 OK\r\nTransfer-Encoding:
chunked\r\nBrokenHeaderNoColon\r\n\r\n");
fclose($conn);
```
client.php (debug build, php -d report_memleaks=1 client.php):
```php
<?php
@file_get_contents("http://127.0.0.1:18231/");
```
Resulted in this output:
```
ext/standard/filters.c(1885) : Freeing 0x... (16 bytes), script=.../client.php
main/streams/filter.c(267) : Freeing 0x... (80 bytes), script=.../client.php
=== Total 2 memory leaks detected ===
```
But I expected this output instead:
```
(no leaks reported)
```
Root cause: when the response carries Transfer-Encoding: chunked, the wrapper creates a
dechunk filter while parsing headers (php_stream_filter_create,
ext/standard/http_fopen_wrapper.c:379 in 8.5.12, :366 on master). If a later header line is
malformed, header_info.error is set, the caller closes the stream and jumps to
out: (master :1052-1058). The out: cleanup only appends the filter to the
stream's readfilters when stream != NULL (master :1257-1259), so on the error path
the filter is never freed. Per failed request this leaks the php_stream_filter struct (80 bytes)
plus the dechunk filter data (16 bytes).
Reproduces on current master (8.7.0-dev) as well.
Suggested patch (verified against master: repro reports 0 leaks after patching; well-formed chunked
responses unaffected):
```diff
--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -1230,6 +1230,13 @@ static php_stream *php_stream_url_wrap_http_ex(php_stream_wrapper *wrapper,
efree(header_info.location);
}
+ /* On the error path stream is NULL and the filter is never appended
+ * to readfilters below, so it must be freed here. */
+ if (header_info.transfer_encoding != NULL && stream == NULL) {
+ php_stream_filter_free(header_info.transfer_encoding);
+ header_info.transfer_encoding = NULL;
+ }
+
if (resource) {
php_uri_struct_free(resource);
}
```
### PHP Version
```plain
PHP 8.5.12 (also reproduces on master, 8.7.0-dev)
```
### Operating System
Linux x86_64