Skip to content

Commit f75931a

Browse files
committed
Fix GH-12929: SimpleXMLElement with stream_wrapper_register can segfault
Move SimpleXML invalidation code after node checks This is safe, i.e. the tree hasn't been modified yet, because either we didn't call a libxml modification function yet, or xmlNewChild is called with a NULL pointer, which makes it bail out and return NULL. Closes GH-12947.
1 parent 4fc336c commit f75931a

File tree

3 files changed

+37
-6
lines changed

3 files changed

+37
-6
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ PHP NEWS
3434
- SimpleXML:
3535
. Fix getting the address of an uninitialized property of a SimpleXMLElement
3636
resulting in a crash. (nielsdos)
37+
. Fixed bug GH-12929 (SimpleXMLElement with stream_wrapper_register can
38+
segfault). (nielsdos)
3739

3840
07 Dec 2023, PHP 8.3.1RC1
3941

ext/simplexml/simplexml.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -421,8 +421,6 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value,
421421

422422
GET_NODE(sxe, node);
423423

424-
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
425-
426424
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
427425
attribs = 1;
428426
elements = 0;
@@ -483,6 +481,8 @@ static zval *sxe_prop_dim_write(zend_object *object, zval *member, zval *value,
483481
}
484482

485483
if (node) {
484+
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
485+
486486
if (attribs) {
487487
if (Z_TYPE_P(member) == IS_LONG) {
488488
while (attr && nodendx <= Z_LVAL_P(member)) {
@@ -797,8 +797,6 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
797797

798798
GET_NODE(sxe, node);
799799

800-
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
801-
802800
if (Z_TYPE_P(member) == IS_LONG) {
803801
if (sxe->iter.type != SXE_ITER_ATTRLIST) {
804802
attribs = 0;
@@ -822,6 +820,8 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
822820
}
823821

824822
if (node) {
823+
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
824+
825825
if (attribs) {
826826
if (Z_TYPE_P(member) == IS_LONG) {
827827
int nodendx = 0;
@@ -1678,8 +1678,6 @@ PHP_METHOD(SimpleXMLElement, addChild)
16781678
sxe = Z_SXEOBJ_P(ZEND_THIS);
16791679
GET_NODE(sxe, node);
16801680

1681-
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
1682-
16831681
if (sxe->iter.type == SXE_ITER_ATTRLIST) {
16841682
php_error_docref(NULL, E_WARNING, "Cannot add element to attributes");
16851683
return;
@@ -1692,6 +1690,8 @@ PHP_METHOD(SimpleXMLElement, addChild)
16921690
return;
16931691
}
16941692

1693+
php_libxml_invalidate_node_list_cache_from_doc(node->doc);
1694+
16951695
localname = xmlSplitQName2((xmlChar *)qname, &prefix);
16961696
if (localname == NULL) {
16971697
localname = xmlStrdup((xmlChar *)qname);

ext/simplexml/tests/gh12929.phpt

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
--TEST--
2+
GH-12929 (SimpleXMLElement with stream_wrapper_register can segfault)
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
$scheme = "foo1";
8+
stream_wrapper_register($scheme, "SimpleXMLIterator");
9+
try {
10+
file_get_contents($scheme . "://x");
11+
} catch (Error $e) {
12+
echo $e->getMessage(), "\n";
13+
echo $e->getPrevious()->getMessage(), "\n";
14+
}
15+
16+
$scheme = "foo2";
17+
stream_wrapper_register($scheme, "SimpleXMLElement");
18+
try {
19+
file_get_contents($scheme . "://x");
20+
} catch (Error $e) {
21+
echo $e->getMessage(), "\n";
22+
echo $e->getPrevious()->getMessage(), "\n";
23+
}
24+
?>
25+
--EXPECT--
26+
It's not possible to assign a complex type to properties, resource given
27+
SimpleXMLElement is not properly initialized
28+
It's not possible to assign a complex type to properties, resource given
29+
SimpleXMLElement is not properly initialized

0 commit comments

Comments
 (0)