Skip to content

Commit 2aea9be

Browse files
committed
Merge branch 'PHP-8.1' into PHP-8.2
* PHP-8.1: Fix memory leak when calling xml_parse_into_struct() twice Fix return type of stub of xml_parse_into_struct()
2 parents 63150dc + 30f26b5 commit 2aea9be

File tree

5 files changed

+55
-13
lines changed

5 files changed

+55
-13
lines changed

NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,10 @@ PHP NEWS
3434
foreach). (nielsdos)
3535
. Fixed bug #55098 (SimpleXML iteration produces infinite loop). (nielsdos)
3636

37+
- XML:
38+
. Fix return type of stub of xml_parse_into_struct(). (nielsdos)
39+
. Fix memory leak when calling xml_parse_into_struct() twice. (nielsdos)
40+
3741
28 Sep 2023, PHP 8.2.11
3842

3943
- Core:

ext/xml/tests/gh12254.phpt

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
--TEST--
2+
GH-12254: xml_parse_into_struct() memory leak when called twice
3+
--EXTENSIONS--
4+
xml
5+
--FILE--
6+
<?php
7+
8+
$parser = xml_parser_create();
9+
xml_set_element_handler($parser, function ($parser, $name, $attrs) {
10+
echo "open\n";
11+
var_dump($name, $attrs);
12+
var_dump(xml_parse_into_struct($parser, "<container/>", $values, $tags));
13+
}, function ($parser, $name) {
14+
echo "close\n";
15+
var_dump($name);
16+
});
17+
xml_parse_into_struct($parser, "<container/>", $values, $tags);
18+
// Yes, this doesn't do anything but it at least shouldn't leak...
19+
xml_parse_into_struct($parser, "<container/>", $values, $tags);
20+
21+
?>
22+
--EXPECTF--
23+
open
24+
string(9) "CONTAINER"
25+
array(0) {
26+
}
27+
28+
Warning: xml_parse_into_struct(): Parser must not be called recursively in %s on line %d
29+
bool(false)
30+
close
31+
string(9) "CONTAINER"

ext/xml/xml.c

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -318,19 +318,24 @@ static zend_object *xml_parser_create_object(zend_class_entry *class_type) {
318318
return &intern->std;
319319
}
320320

321-
static void xml_parser_free_obj(zend_object *object)
321+
static void xml_parser_free_ltags(xml_parser *parser)
322322
{
323-
xml_parser *parser = xml_parser_from_obj(object);
324-
325-
if (parser->parser) {
326-
XML_ParserFree(parser->parser);
327-
}
328323
if (parser->ltags) {
329324
int inx;
330325
for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++)
331326
efree(parser->ltags[ inx ]);
332327
efree(parser->ltags);
333328
}
329+
}
330+
331+
static void xml_parser_free_obj(zend_object *object)
332+
{
333+
xml_parser *parser = xml_parser_from_obj(object);
334+
335+
if (parser->parser) {
336+
XML_ParserFree(parser->parser);
337+
}
338+
xml_parser_free_ltags(parser);
334339
if (!Z_ISUNDEF(parser->startElementHandler)) {
335340
zval_ptr_dtor(&parser->startElementHandler);
336341
}
@@ -1261,6 +1266,11 @@ PHP_FUNCTION(xml_parse_into_struct)
12611266

12621267
parser = Z_XMLPARSER_P(pind);
12631268

1269+
if (parser->isparsing) {
1270+
php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
1271+
RETURN_FALSE;
1272+
}
1273+
12641274
if (info) {
12651275
info = zend_try_array_init(info);
12661276
if (!info) {
@@ -1280,15 +1290,12 @@ PHP_FUNCTION(xml_parse_into_struct)
12801290
}
12811291

12821292
parser->level = 0;
1293+
xml_parser_free_ltags(parser);
12831294
parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0);
12841295

12851296
XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler);
12861297
XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler);
12871298

1288-
if (parser->isparsing) {
1289-
php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
1290-
RETURN_FALSE;
1291-
}
12921299
parser->isparsing = 1;
12931300
ret = XML_Parse(parser->parser, (XML_Char*)data, data_len, 1);
12941301
parser->isparsing = 0;

ext/xml/xml.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,7 @@ function xml_parse(XMLParser $parser, string $data, bool $is_final = false): int
176176
* @param array $values
177177
* @param array $index
178178
*/
179-
function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int {}
179+
function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int|false {}
180180

181181
function xml_get_error_code(XMLParser $parser): int {}
182182

ext/xml/xml_arginfo.h

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)