Hacktoberfest 2026 : les issues que les mainteneurs ont marquées pour octobre, ouvertes et accessibles aux débutants. Parcourir les issues Hacktoberfest

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

Ouverte Adaptée aux débutants
#24,509 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub

Les mainteneurs répondent en général sous 1 jour

Personne n'a encore pris cette issue.

Évaluation

Difficulté
2/5
Temps estimé
1-3 heures
Accessibilité débutants
78/100
Type d'issue
Bug
Clarté
Clairement spécifiée
Activité
Active
Stack technique
c, php
Domaine
backend, networking

Piste de recherche

Commencez dans ext/standard/http_fopen_wrapper.c, au niveau de php_stream_http_response_headers_parse(), et examinez comment les en-têtes Location répétés allouent et redimensionnent le tampon. Le rapport inclut une reproduction de la fuite avec server.php et client.php ; exécutez-la avec une compilation de débogage de PHP et report_memleaks=1. Le travail est terminé lorsque la séquence d’un en-tête vide puis non vide ne signale aucune fuite, tandis que les en-têtes Location non vides répétés se comportent toujours comme décrit.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Description

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

Langage dominant
C
Étoiles
40.4k
Forks
8.2k
Merge moyen
2 j 22 h
PR mergées (30 j)
166

Préparer son environnement

Par où commencer

  1. Lisez l'issue en entier, puis le guide de contribution du projet.
  2. Signalez en commentaire que vous la prenez — cela évite que deux personnes fassent le même travail.
  3. Forkez le dépôt et travaillez sur une branche.
  4. Ouvrez une pull request qui référence le numéro de l'issue.

Autres issues de php/php-src

Toutes les issues de php/php-src

Issues similaires

Plus d'issues C

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.