Skip to content

Commit 2bbe4fd

Browse files
committed
Merge branch 'PHP-8.2' into PHP-8.3
* PHP-8.2: Fix memory leak when calling xml_parse_into_struct() twice Fix return type of stub of xml_parse_into_struct()
2 parents 35a502f + 2aea9be commit 2bbe4fd

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
@@ -35,6 +35,10 @@ PHP NEWS
3535
foreach). (nielsdos)
3636
. Fixed bug #55098 (SimpleXML iteration produces infinite loop). (nielsdos)
3737

38+
- XML:
39+
. Fix return type of stub of xml_parse_into_struct(). (nielsdos)
40+
. Fix memory leak when calling xml_parse_into_struct() twice. (nielsdos)
41+
3842
14 Sep 2023, PHP 8.3.0RC2
3943

4044
- 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
@@ -312,19 +312,24 @@ static zend_object *xml_parser_create_object(zend_class_entry *class_type) {
312312
return &intern->std;
313313
}
314314

315-
static void xml_parser_free_obj(zend_object *object)
315+
static void xml_parser_free_ltags(xml_parser *parser)
316316
{
317-
xml_parser *parser = xml_parser_from_obj(object);
318-
319-
if (parser->parser) {
320-
XML_ParserFree(parser->parser);
321-
}
322317
if (parser->ltags) {
323318
int inx;
324319
for (inx = 0; ((inx < parser->level) && (inx < XML_MAXLEVEL)); inx++)
325320
efree(parser->ltags[ inx ]);
326321
efree(parser->ltags);
327322
}
323+
}
324+
325+
static void xml_parser_free_obj(zend_object *object)
326+
{
327+
xml_parser *parser = xml_parser_from_obj(object);
328+
329+
if (parser->parser) {
330+
XML_ParserFree(parser->parser);
331+
}
332+
xml_parser_free_ltags(parser);
328333
if (!Z_ISUNDEF(parser->startElementHandler)) {
329334
zval_ptr_dtor(&parser->startElementHandler);
330335
}
@@ -1255,6 +1260,11 @@ PHP_FUNCTION(xml_parse_into_struct)
12551260

12561261
parser = Z_XMLPARSER_P(pind);
12571262

1263+
if (parser->isparsing) {
1264+
php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
1265+
RETURN_FALSE;
1266+
}
1267+
12581268
if (info) {
12591269
info = zend_try_array_init(info);
12601270
if (!info) {
@@ -1274,15 +1284,12 @@ PHP_FUNCTION(xml_parse_into_struct)
12741284
}
12751285

12761286
parser->level = 0;
1287+
xml_parser_free_ltags(parser);
12771288
parser->ltags = safe_emalloc(XML_MAXLEVEL, sizeof(char *), 0);
12781289

12791290
XML_SetElementHandler(parser->parser, _xml_startElementHandler, _xml_endElementHandler);
12801291
XML_SetCharacterDataHandler(parser->parser, _xml_characterDataHandler);
12811292

1282-
if (parser->isparsing) {
1283-
php_error_docref(NULL, E_WARNING, "Parser must not be called recursively");
1284-
RETURN_FALSE;
1285-
}
12861293
parser->isparsing = 1;
12871294
ret = XML_Parse(parser->parser, (XML_Char*)data, data_len, 1);
12881295
parser->isparsing = 0;

ext/xml/xml.stub.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -182,7 +182,7 @@ function xml_parse(XMLParser $parser, string $data, bool $is_final = false): int
182182
* @param array $values
183183
* @param array $index
184184
*/
185-
function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int {}
185+
function xml_parse_into_struct(XMLParser $parser, string $data, &$values, &$index = null): int|false {}
186186

187187
function xml_get_error_code(XMLParser $parser): int {}
188188

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)