Skip to content

Commit aab6bbc

Browse files
committed
Merge branch 'PHP-8.3'
* PHP-8.3: Fix GH-12215: Module entry being overwritten causes type errors in ext/dom (<= PHP 8.3) Fix bug #55098: SimpleXML iteration produces infinite loop
2 parents 37ce719 + b08802d commit aab6bbc

File tree

3 files changed

+120
-39
lines changed

3 files changed

+120
-39
lines changed

ext/simplexml/simplexml.c

Lines changed: 26 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -77,17 +77,6 @@ static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE
7777
}
7878
/* }}} */
7979

80-
/* Important: this overwrites the iterator data, if you wish to keep it use php_sxe_get_first_node_non_destructive() instead! */
81-
static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node) /* {{{ */
82-
{
83-
if (sxe && sxe->iter.type != SXE_ITER_NONE) {
84-
return php_sxe_reset_iterator(sxe, 1);
85-
} else {
86-
return node;
87-
}
88-
}
89-
/* }}} */
90-
9180
static xmlNodePtr php_sxe_get_first_node_non_destructive(php_sxe_object *sxe, xmlNodePtr node)
9281
{
9382
if (sxe && sxe->iter.type != SXE_ITER_NONE) {
@@ -170,7 +159,7 @@ static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node,
170159
if (sxe->iter.type == SXE_ITER_NONE) {
171160
sxe->iter.type = SXE_ITER_CHILD;
172161
}
173-
node = php_sxe_get_first_node(sxe, node);
162+
node = php_sxe_get_first_node_non_destructive(sxe, node);
174163
sxe->iter.type = orgtype;
175164
}
176165

@@ -243,11 +232,11 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements,
243232
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
244233
attribs = 1;
245234
elements = 0;
246-
node = php_sxe_get_first_node(sxe, node);
235+
node = php_sxe_get_first_node_non_destructive(sxe, node);
247236
attr = (xmlAttrPtr)node;
248237
test = sxe->iter.name != NULL;
249238
} else if (sxe->iter.type != SXE_ITER_CHILD) {
250-
node = php_sxe_get_first_node(sxe, node);
239+
node = php_sxe_get_first_node_non_destructive(sxe, node);
251240
attr = node ? node->properties : NULL;
252241
test = 0;
253242
if (!member && node && node->parent &&
@@ -295,7 +284,7 @@ static zval *sxe_prop_dim_read(zend_object *object, zval *member, bool elements,
295284
xmlNodePtr mynode = node;
296285

297286
if (sxe->iter.type == SXE_ITER_CHILD) {
298-
node = php_sxe_get_first_node(sxe, node);
287+
node = php_sxe_get_first_node_non_destructive(sxe, node);
299288
}
300289
if (sxe->iter.type == SXE_ITER_NONE) {
301290
if (member && Z_LVAL_P(member) > 0) {
@@ -431,12 +420,12 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value,
431420
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
432421
attribs = 1;
433422
elements = 0;
434-
node = php_sxe_get_first_node(sxe, node);
423+
node = php_sxe_get_first_node_non_destructive(sxe, node);
435424
attr = (xmlAttrPtr)node;
436425
test = sxe->iter.name != NULL;
437426
} else if (sxe->iter.type != SXE_ITER_CHILD) {
438427
mynode = node;
439-
node = php_sxe_get_first_node(sxe, node);
428+
node = php_sxe_get_first_node_non_destructive(sxe, node);
440429
attr = node ? node->properties : NULL;
441430
test = 0;
442431
if (!member && node && node->parent &&
@@ -682,19 +671,19 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
682671
attribs = 0;
683672
elements = 1;
684673
if (sxe->iter.type == SXE_ITER_CHILD) {
685-
node = php_sxe_get_first_node(sxe, node);
674+
node = php_sxe_get_first_node_non_destructive(sxe, node);
686675
}
687676
}
688677
}
689678

690679
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
691680
attribs = 1;
692681
elements = 0;
693-
node = php_sxe_get_first_node(sxe, node);
682+
node = php_sxe_get_first_node_non_destructive(sxe, node);
694683
attr = (xmlAttrPtr)node;
695684
test = sxe->iter.name != NULL;
696685
} else if (sxe->iter.type != SXE_ITER_CHILD) {
697-
node = php_sxe_get_first_node(sxe, node);
686+
node = php_sxe_get_first_node_non_destructive(sxe, node);
698687
attr = node ? node->properties : NULL;
699688
test = 0;
700689
}
@@ -734,7 +723,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
734723
if (elements) {
735724
if (Z_TYPE_P(member) == IS_LONG) {
736725
if (sxe->iter.type == SXE_ITER_CHILD) {
737-
node = php_sxe_get_first_node(sxe, node);
726+
node = php_sxe_get_first_node_non_destructive(sxe, node);
738727
}
739728
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
740729
} else {
@@ -806,19 +795,19 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
806795
attribs = 0;
807796
elements = 1;
808797
if (sxe->iter.type == SXE_ITER_CHILD) {
809-
node = php_sxe_get_first_node(sxe, node);
798+
node = php_sxe_get_first_node_non_destructive(sxe, node);
810799
}
811800
}
812801
}
813802

814803
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
815804
attribs = 1;
816805
elements = 0;
817-
node = php_sxe_get_first_node(sxe, node);
806+
node = php_sxe_get_first_node_non_destructive(sxe, node);
818807
attr = (xmlAttrPtr)node;
819808
test = sxe->iter.name != NULL;
820809
} else if (sxe->iter.type != SXE_ITER_CHILD) {
821-
node = php_sxe_get_first_node(sxe, node);
810+
node = php_sxe_get_first_node_non_destructive(sxe, node);
822811
attr = node ? node->properties : NULL;
823812
test = 0;
824813
}
@@ -855,7 +844,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
855844
if (elements) {
856845
if (Z_TYPE_P(member) == IS_LONG) {
857846
if (sxe->iter.type == SXE_ITER_CHILD) {
858-
node = php_sxe_get_first_node(sxe, node);
847+
node = php_sxe_get_first_node_non_destructive(sxe, node);
859848
}
860849
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
861850
if (node) {
@@ -987,7 +976,7 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
987976
}
988977

989978
if (sxe->iter.type == SXE_ITER_ELEMENT) {
990-
node = php_sxe_get_first_node(sxe, node);
979+
node = php_sxe_get_first_node_non_destructive(sxe, node);
991980
}
992981
if (node && node->type != XML_ENTITY_DECL) {
993982
attr = node->properties;
@@ -1001,7 +990,7 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
1001990
}
1002991

1003992
GET_NODE(sxe, node);
1004-
node = php_sxe_get_first_node(sxe, node);
993+
node = php_sxe_get_first_node_non_destructive(sxe, node);
1005994
is_empty = 1;
1006995
if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
1007996
if (node->type == XML_ATTRIBUTE_NODE) {
@@ -1083,7 +1072,7 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
10831072
}
10841073
if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
10851074
if (sxe->iter.type == SXE_ITER_ELEMENT) {
1086-
node = php_sxe_get_first_node(sxe, node);
1075+
node = php_sxe_get_first_node_non_destructive(sxe, node);
10871076
}
10881077
if (node && node->type != XML_ENTITY_DECL) {
10891078
attr = node->properties;
@@ -1105,7 +1094,7 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
11051094
}
11061095

11071096
GET_NODE(sxe, node);
1108-
node = php_sxe_get_first_node(sxe, node);
1097+
node = php_sxe_get_first_node_non_destructive(sxe, node);
11091098

11101099
if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
11111100
if (node->type == XML_ATTRIBUTE_NODE) {
@@ -1252,7 +1241,7 @@ PHP_METHOD(SimpleXMLElement, xpath)
12521241
}
12531242

12541243
GET_NODE(sxe, nodeptr);
1255-
nodeptr = php_sxe_get_first_node(sxe, nodeptr);
1244+
nodeptr = php_sxe_get_first_node_non_destructive(sxe, nodeptr);
12561245
if (!nodeptr) {
12571246
return;
12581247
}
@@ -1362,7 +1351,7 @@ PHP_METHOD(SimpleXMLElement, asXML)
13621351

13631352
sxe = Z_SXEOBJ_P(ZEND_THIS);
13641353
GET_NODE(sxe, node);
1365-
node = php_sxe_get_first_node(sxe, node);
1354+
node = php_sxe_get_first_node_non_destructive(sxe, node);
13661355

13671356
if (!node) {
13681357
RETURN_FALSE;
@@ -1480,7 +1469,7 @@ PHP_METHOD(SimpleXMLElement, getNamespaces)
14801469

14811470
sxe = Z_SXEOBJ_P(ZEND_THIS);
14821471
GET_NODE(sxe, node);
1483-
node = php_sxe_get_first_node(sxe, node);
1472+
node = php_sxe_get_first_node_non_destructive(sxe, node);
14841473

14851474
if (node) {
14861475
if (node->type == XML_ELEMENT_NODE) {
@@ -1565,7 +1554,7 @@ PHP_METHOD(SimpleXMLElement, children)
15651554
}
15661555

15671556
GET_NODE(sxe, node);
1568-
node = php_sxe_get_first_node(sxe, node);
1557+
node = php_sxe_get_first_node_non_destructive(sxe, node);
15691558
if (!node) {
15701559
return;
15711560
}
@@ -1614,7 +1603,7 @@ PHP_METHOD(SimpleXMLElement, attributes)
16141603

16151604
sxe = Z_SXEOBJ_P(ZEND_THIS);
16161605
GET_NODE(sxe, node);
1617-
node = php_sxe_get_first_node(sxe, node);
1606+
node = php_sxe_get_first_node_non_destructive(sxe, node);
16181607
if (!node) {
16191608
return;
16201609
}
@@ -1657,7 +1646,7 @@ PHP_METHOD(SimpleXMLElement, addChild)
16571646
return;
16581647
}
16591648

1660-
node = php_sxe_get_first_node(sxe, node);
1649+
node = php_sxe_get_first_node_non_destructive(sxe, node);
16611650

16621651
if (node == NULL) {
16631652
php_error_docref(NULL, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
@@ -1717,7 +1706,7 @@ PHP_METHOD(SimpleXMLElement, addAttribute)
17171706
sxe = Z_SXEOBJ_P(ZEND_THIS);
17181707
GET_NODE(sxe, node);
17191708

1720-
node = php_sxe_get_first_node(sxe, node);
1709+
node = php_sxe_get_first_node_non_destructive(sxe, node);
17211710

17221711
if (node && node->type != XML_ELEMENT_NODE) {
17231712
node = node->parent;
@@ -2550,7 +2539,7 @@ void *simplexml_export_node(zval *object) /* {{{ */
25502539

25512540
sxe = Z_SXEOBJ_P(object);
25522541
GET_NODE(sxe, node);
2553-
return php_sxe_get_first_node(sxe, node);
2542+
return php_sxe_get_first_node_non_destructive(sxe, node);
25542543
}
25552544
/* }}} */
25562545

ext/simplexml/tests/bug55098.phpt

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
--TEST--
2+
Bug #55098 (SimpleXML iteration produces infinite loop)
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
$xmlString = "<root><a><b>1</b><b>2</b><b>3</b></a></root>";
8+
$xml = simplexml_load_string($xmlString);
9+
10+
$nodes = $xml->a->b;
11+
12+
function test($nodes, $name, $callable) {
13+
echo "--- $name ---\n";
14+
foreach ($nodes as $nodeData) {
15+
echo "nodeData: " . $nodeData . "\n";
16+
$callable($nodes);
17+
}
18+
}
19+
20+
test($nodes, "asXml", fn ($n) => $n->asXml());
21+
test($nodes, "attributes", fn ($n) => $n->attributes());
22+
test($nodes, "children", fn ($n) => $n->children());
23+
test($nodes, "getNamespaces", fn ($n) => $n->getNamespaces());
24+
test($nodes, "xpath", fn ($n) => $n->xpath("/root/a/b"));
25+
test($nodes, "var_dump", fn ($n) => var_dump($n));
26+
test($nodes, "manipulation combined with querying", function ($n) {
27+
$n->addAttribute("attr", "value");
28+
(bool) $n["attr"];
29+
$n->addChild("child", "value");
30+
$n->outer[]->inner = "foo";
31+
(bool) $n->outer;
32+
(bool) $n;
33+
isset($n->outer);
34+
isset($n["attr"]);
35+
unset($n->outer);
36+
unset($n["attr"]);
37+
unset($n->child);
38+
});
39+
?>
40+
--EXPECT--
41+
--- asXml ---
42+
nodeData: 1
43+
nodeData: 2
44+
nodeData: 3
45+
--- attributes ---
46+
nodeData: 1
47+
nodeData: 2
48+
nodeData: 3
49+
--- children ---
50+
nodeData: 1
51+
nodeData: 2
52+
nodeData: 3
53+
--- getNamespaces ---
54+
nodeData: 1
55+
nodeData: 2
56+
nodeData: 3
57+
--- xpath ---
58+
nodeData: 1
59+
nodeData: 2
60+
nodeData: 3
61+
--- var_dump ---
62+
nodeData: 1
63+
object(SimpleXMLElement)#3 (3) {
64+
[0]=>
65+
string(1) "1"
66+
[1]=>
67+
string(1) "2"
68+
[2]=>
69+
string(1) "3"
70+
}
71+
nodeData: 2
72+
object(SimpleXMLElement)#3 (3) {
73+
[0]=>
74+
string(1) "1"
75+
[1]=>
76+
string(1) "2"
77+
[2]=>
78+
string(1) "3"
79+
}
80+
nodeData: 3
81+
object(SimpleXMLElement)#3 (3) {
82+
[0]=>
83+
string(1) "1"
84+
[1]=>
85+
string(1) "2"
86+
[2]=>
87+
string(1) "3"
88+
}
89+
--- manipulation combined with querying ---
90+
nodeData: 1
91+
nodeData: 2
92+
nodeData: 3

ext/simplexml/tests/bug62639.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ foreach ($a2->b->c->children() as $key => $value) {
4141
var_dump($value);
4242
}?>
4343
--EXPECT--
44-
object(A)#2 (2) {
44+
object(A)#4 (2) {
4545
["@attributes"]=>
4646
array(1) {
4747
["attr"]=>
@@ -50,7 +50,7 @@ object(A)#2 (2) {
5050
[0]=>
5151
string(10) "Some Value"
5252
}
53-
object(A)#3 (2) {
53+
object(A)#6 (2) {
5454
["@attributes"]=>
5555
array(1) {
5656
["attr"]=>

0 commit comments

Comments
 (0)