Hacktoberfest 2026:維護者為十月標記出來的 issue,仍然開放、適合新手。 瀏覽 Hacktoberfest issue

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

未關閉 適合新手
#24,509 0 則留言 0 個 reaction 已指派 0 人 在 GitHub 檢視

維護者通常 1 天內回覆

還沒有人認領這個 Issue。

評估

難度
2/5
預估耗時
1-3 小時
新手友好度
78/100
Issue 類型
缺陷
描述清晰度
描述清楚
活躍度
活躍
技術堆疊
c, php

研究方向

從ext/standard/http_fopen_wrapper.c中的php_stream_http_response_headers_parse()開始,檢查重複的Location標頭如何配置和調整緩衝區大小。報告包含使用server.php和client.php重現記憶體洩漏的方法;使用除錯版 PHP 建置並設定report_memleaks=1執行。完成標準是:空標頭之後接非空標頭的序列不再回報洩漏,同時重複的非空Location標頭仍依描述運作。

由索引模型根據 Issue 內容生成。

描述

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

主要語言
C
星號
40.4k
分支
8.2k
平均合併
2 天 22 小時
30 天內合併 PR
166

環境準備

  • 沒有 Dockerfile 或 Docker Compose 檔案
  • 沒有 Pull Request 範本
  • 閱讀貢獻指南

從這裡開始

  1. 先讀完整個 Issue,再讀專案的貢獻指南。
  2. 在 Issue 下留言說明你要接手 —— 這能避免兩個人做同樣的事。
  3. Fork 儲存庫,在一個分支上完成修改。
  4. 送出 Pull Request,並在描述裡引用這個 Issue 編號。

php/php-src 的其他 Issue

查看 php/php-src 的全部 Issue

相似的 Issue

更多 C Issue

把新 issue 寄到你的電子郵件信箱

精選適合新手參與的 GitHub issue 摘要。