Hacktoberfest 2026: die Issues, die Maintainer für den Oktober markiert haben – offen und einsteigerfreundlich. Hacktoberfest-Issues durchsuchen

HTTP wrapper leaks Location buffer when an empty Location header is followed by another Location header

Offen Anfängerfreundlich
#24,509 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen

Maintainer antworten meist innerhalb von 1 Tag

Dieses Issue hat noch niemand übernommen.

Bewertung

Schwierigkeit
2/5
Geschätzter Aufwand
1-3 Stunden
Anfängerfreundlichkeit
78/100
Issue-Typ
Bug
Klarheit
Klar beschrieben
Aktivitätsstatus
Aktiv
Tech-Stack
c, php
Bereich
backend, networking

Rechercherichtung

Beginne in ext/standard/http_fopen_wrapper.c bei php_stream_http_response_headers_parse() und untersuche, wie wiederholte Location-Header den Puffer allokieren und vergrößern. Der Bericht enthält eine Leak-Reproduktion mit server.php und client.php; führe sie mit einem Debug-PHP-Build und report_memleaks=1 aus. Als erledigt gilt die Aufgabe, wenn die Folge aus einem leeren und anschließend einem nicht leeren Header keinen Leak meldet, während sich wiederholte nicht leere Location-Header weiterhin wie beschrieben verhalten.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Beschreibung

Bug Status: Needs Triage
Description

The following code:

server.php (run first, php server.php):

<?php
$srv = stream_socket_server("tcp://127.0.0.1:18233", $errno, $errstr);
$conn = stream_socket_accept($srv);
while (($line = fgets($conn, 8192)) !== false) { if (trim($line) === '') break; }
// empty Location value, then a real one
fwrite($conn, "HTTP/1.1 302 Found\r\nLocation:\r\nLocation: /abcdefghijklmno\r\n\r\n");
fclose($conn);

client.php (debug build, php -d report_memleaks=1 client.php):

<?php
@file_get_contents("http://127.0.0.1:18233/");

Resulted in this output:

ext/standard/http_fopen_wrapper.c(341) :  Freeing 0x... (16 bytes), script=.../client.php
=== Total 1 memory leaks detected ===

But I expected this output instead:

(no leaks reported)

Root cause: the wrapper stores the Location value using location_len == 0 as the "nothing allocated yet" sentinel (ext/standard/http_fopen_wrapper.c:340 in 8.5.12, :327 on master):

if (header_info->location_len == 0) {
    header_info->location = emalloc(last_header_value_len + 1);
} else if (header_info->location_len <= last_header_value_len) {
    header_info->location = erealloc(header_info->location, last_header_value_len + 1);
}
header_info->location_len = last_header_value_len;

An empty Location: header allocates a 1-byte buffer and then sets location_len = 0, restoring the sentinel state while the pointer is still held. A second Location header takes the emalloc branch again and the first buffer is leaked. Each empty-then-nonempty sequence leaks one buffer per request.

Control (two non-empty Location headers): 0 leaks. Reproduces on current master (8.7.0-dev) as well.

Suggested patch (verified against master: 0 leaks after patching; repeated non-empty Location headers still take the erealloc path and behave as before). header_info is zero-initialized by php_stream_http_response_header_info_init, so the pointer works as the sentinel:

--- a/ext/standard/http_fopen_wrapper.c
+++ b/ext/standard/http_fopen_wrapper.c
@@ -324,7 +324,9 @@ static zend_string *php_stream_http_response_headers_parse(php_stream_wrapper *w
 			zend_string_efree(last_header_line);
 			return NULL;
 		}
-		if (header_info->location_len == 0) {
+		/* An empty Location value leaves location_len at 0, so the buffer
+		 * pointer, not the length, must be the "already allocated" test. */
+		if (header_info->location == NULL) {
 			header_info->location = emalloc(last_header_value_len + 1);
 		} else if (header_info->location_len <= last_header_value_len) {
 			header_info->location = erealloc(header_info->location, last_header_value_len + 1);
PHP Version
PHP 8.5.12 (also reproduces on master, 8.7.0-dev)
Operating System

Linux x86_64

Vorherrschende Sprache
C
Sterne
40.7k
Forks
8.3k
Ø Merge
17 Std. 29 Min.
Gemergte PRs (30 T.)
10

Entwicklungsumgebung

Erste Schritte

  1. Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
  2. Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
  3. Forken Sie das Repository und arbeiten Sie in einem Branch.
  4. Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.

Mehr aus php/php-src

Alle Issues in php/php-src

Ähnliche Issues

Weitere Issues zu C

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.