diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index 57c0627d61a6a..33dc7bac32701 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1186,6 +1186,12 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */ sxe_properties_add(rv, name, namelen, &value); } next_iter: + if (UNEXPECTED(node->type == XML_ENTITY_DECL)) { + /* Entity decls are linked together via the next pointer. + * The only way to get to an entity decl is via an entity reference in the document. + * If we then continue iterating, we'll end up in the DTD. Even worse, if the entities reference each other we'll infinite loop. */ + break; + } if (use_iter) { node = php_sxe_iterator_fetch(sxe, node->next, 0); } else { diff --git a/ext/simplexml/tests/gh12223.phpt b/ext/simplexml/tests/gh12223.phpt new file mode 100644 index 0000000000000..0be61dec2ffa6 --- /dev/null +++ b/ext/simplexml/tests/gh12223.phpt @@ -0,0 +1,67 @@ +--TEST-- +GH-12223: Entity reference produces infinite loop in var_dump/print_r +--EXTENSIONS-- +simplexml +--FILE-- + + + + +]> +&c; +XML; + +$sxe = simplexml_load_string($xml); + +var_dump($sxe); +print_r($sxe); + +?> +--EXPECT-- +object(SimpleXMLElement)#1 (1) { + ["c"]=> + object(SimpleXMLElement)#2 (1) { + ["c"]=> + object(SimpleXMLElement)#3 (1) { + ["b"]=> + object(SimpleXMLElement)#4 (1) { + ["b"]=> + object(SimpleXMLElement)#5 (1) { + ["a"]=> + object(SimpleXMLElement)#6 (1) { + ["a"]=> + string(9) "something" + } + } + } + } + } +} +SimpleXMLElement Object +( + [c] => SimpleXMLElement Object + ( + [c] => SimpleXMLElement Object + ( + [b] => SimpleXMLElement Object + ( + [b] => SimpleXMLElement Object + ( + [a] => SimpleXMLElement Object + ( + [a] => something + ) + + ) + + ) + + ) + + ) + +)