diff --git a/ext/simplexml/simplexml.c b/ext/simplexml/simplexml.c index eebf4af0239..1047fb4f19c 100644 --- a/ext/simplexml/simplexml.c +++ b/ext/simplexml/simplexml.c @@ -1493,6 +1493,35 @@ static void sxe_add_namespaces(php_sxe_object *sxe, xmlNodePtr node, bool recurs } } /* }}} */ +static inline void sxe_object_free_iterxpath(php_sxe_object *sxe) +{ + if (!Z_ISUNDEF(sxe->iter.data)) { + zval_ptr_dtor(&sxe->iter.data); + ZVAL_UNDEF(&sxe->iter.data); + } + + if (sxe->iter.name) { + efree(sxe->iter.name); + sxe->iter.name = NULL; + } + if (sxe->iter.nsprefix) { + efree(sxe->iter.nsprefix); + sxe->iter.nsprefix = NULL; + } + if (!Z_ISUNDEF(sxe->tmp)) { + zval_ptr_dtor(&sxe->tmp); + ZVAL_UNDEF(&sxe->tmp); + } + + php_libxml_node_decrement_resource((php_libxml_node_object *)sxe); + + if (sxe->xpath) { + xmlXPathFreeContext(sxe->xpath); + sxe->xpath = NULL; + } +} + + /* {{{ Return all namespaces in use */ PHP_METHOD(SimpleXMLElement, getNamespaces) { @@ -2149,29 +2178,7 @@ static void sxe_object_free_storage(zend_object *object) zend_object_std_dtor(&sxe->zo); - if (!Z_ISUNDEF(sxe->iter.data)) { - zval_ptr_dtor(&sxe->iter.data); - ZVAL_UNDEF(&sxe->iter.data); - } - - if (sxe->iter.name) { - efree(sxe->iter.name); - sxe->iter.name = NULL; - } - if (sxe->iter.nsprefix) { - efree(sxe->iter.nsprefix); - sxe->iter.nsprefix = NULL; - } - if (!Z_ISUNDEF(sxe->tmp)) { - zval_ptr_dtor(&sxe->tmp); - ZVAL_UNDEF(&sxe->tmp); - } - - php_libxml_node_decrement_resource((php_libxml_node_object *)sxe); - - if (sxe->xpath) { - xmlXPathFreeContext(sxe->xpath); - } + sxe_object_free_iterxpath(sxe); if (sxe->properties) { zend_hash_destroy(sxe->properties); @@ -2371,11 +2378,12 @@ PHP_METHOD(SimpleXMLElement, __construct) PHP_LIBXML_RESTORE_GLOBALS(read_file_or_memory); if (!docp) { - ((php_libxml_node_object *)sxe)->document = NULL; zend_throw_exception(zend_ce_exception, "String could not be parsed as XML", 0); RETURN_THROWS(); } + sxe_object_free_iterxpath(sxe); + sxe->iter.nsprefix = ns_len ? (xmlChar*)estrdup(ns) : NULL; sxe->iter.isprefix = isprefix; php_libxml_increment_doc_ref((php_libxml_node_object *)sxe, docp); diff --git a/ext/simplexml/tests/gh14638.phpt b/ext/simplexml/tests/gh14638.phpt new file mode 100644 index 00000000000..abb4e1ac140 --- /dev/null +++ b/ext/simplexml/tests/gh14638.phpt @@ -0,0 +1,25 @@ +--TEST-- +GH-14638: null pointer dereference on object cast __toString after failed XML parsing +--EXTENSIONS-- +simplexml +--CREDITS-- +YuanchengJiang +--FILE-- + + +'; +$root = simplexml_load_string($xml); +try { + $root->__construct("malformed"); +} catch (Exception $e) { + // Intentionally empty +} +echo $root; +?> +--EXPECTF-- +Warning: SimpleXMLElement::__construct(): Entity: line 1: parser error : Start tag expected, '<' not found in %s on line %d + +Warning: SimpleXMLElement::__construct(): malformed in %s on line %d + +Warning: SimpleXMLElement::__construct(): ^ in %s on line %d