1
0
mirror of https://github.com/php/php-src.git synced 2026-03-24 00:02:20 +01:00

Merge branch 'PHP-8.4'

* PHP-8.4:
  Fix various document ref pointer mismanagements
This commit is contained in:
Niels Dossche
2024-10-17 21:21:56 +02:00
6 changed files with 111 additions and 20 deletions

View File

@@ -734,9 +734,8 @@ static void dom_element_set_attribute_node_common(INTERNAL_FUNCTION_PARAMETERS,
xmlUnlinkNode((xmlNodePtr) attrp);
}
if (attrp->doc == NULL && nodep->doc != NULL) {
attrobj->document = intern->document;
php_libxml_increment_doc_ref((php_libxml_node_object *)attrobj, NULL);
if (attrp->doc == NULL && nodep->doc != NULL && intern->document != NULL) {
dom_set_document_ref_pointers_attr(attrp, intern->document);
}
xmlAddChild(nodep, (xmlNodePtr) attrp);

View File

@@ -740,11 +740,14 @@ zend_result dom_node_text_content_write(dom_object *obj, zval *newval)
/* }}} */
/* Returns true if the node was changed, false otherwise. */
static bool dom_set_document_ref_obj_single(xmlNodePtr node, xmlDocPtr doc, php_libxml_ref_obj *document)
/* Returns true if the node had the same document reference, false otherwise. */
static bool dom_set_document_ref_obj_single(xmlNodePtr node, php_libxml_ref_obj *document)
{
dom_object *childobj = php_dom_object_get_data(node);
if (childobj && !childobj->document) {
if (!childobj) {
return true;
}
if (!childobj->document) {
childobj->document = document;
document->refcount++;
return true;
@@ -752,24 +755,46 @@ static bool dom_set_document_ref_obj_single(xmlNodePtr node, xmlDocPtr doc, php_
return false;
}
static void dom_set_document_pointers(xmlNodePtr node, xmlDocPtr doc, php_libxml_ref_obj *document)
void dom_set_document_ref_pointers_attr(xmlAttrPtr attr, php_libxml_ref_obj *document)
{
/* Applies the document to the entire subtree. */
xmlSetTreeDoc(node, doc);
ZEND_ASSERT(document != NULL);
if (!dom_set_document_ref_obj_single(node, doc, document)) {
dom_set_document_ref_obj_single((xmlNodePtr) attr, document);
for (xmlNodePtr attr_child = attr->children; attr_child; attr_child = attr_child->next) {
dom_set_document_ref_obj_single(attr_child, document);
}
}
static bool dom_set_document_ref_pointers_node(xmlNodePtr node, php_libxml_ref_obj *document)
{
ZEND_ASSERT(document != NULL);
if (!dom_set_document_ref_obj_single(node, document)) {
return false;
}
if (node->type == XML_ELEMENT_NODE) {
for (xmlAttrPtr attr = node->properties; attr; attr = attr->next) {
dom_set_document_ref_pointers_attr(attr, document);
}
}
return true;
}
void dom_set_document_ref_pointers(xmlNodePtr node, php_libxml_ref_obj *document)
{
if (!document) {
return;
}
if (!dom_set_document_ref_pointers_node(node, document)) {
return;
}
xmlNodePtr base = node;
node = node->children;
while (node != NULL) {
ZEND_ASSERT(node != base);
if (!dom_set_document_ref_obj_single(node, doc, document)) {
break;
}
while (node != NULL && dom_set_document_ref_pointers_node(node, document)) {
node = php_dom_next_in_tree_order(node, base);
}
}
@@ -860,7 +885,7 @@ static void dom_node_insert_before_legacy(zval *return_value, zval *ref, dom_obj
}
if (child->doc == NULL && parentp->doc != NULL) {
dom_set_document_pointers(child, parentp->doc, intern->document);
dom_set_document_ref_pointers(child, intern->document);
}
php_libxml_invalidate_node_list_cache(intern->document);
@@ -1167,7 +1192,7 @@ static void dom_node_replace_child(INTERNAL_FUNCTION_PARAMETERS, bool modern)
}
if (newchild->doc == NULL && nodep->doc != NULL) {
dom_set_document_pointers(newchild, nodep->doc, intern->document);
dom_set_document_ref_pointers(newchild, intern->document);
}
if (newchild->type == XML_DOCUMENT_FRAG_NODE) {
@@ -1275,7 +1300,7 @@ static void dom_node_append_child_legacy(zval *return_value, dom_object *intern,
}
if (child->doc == NULL && nodep->doc != NULL) {
dom_set_document_pointers(child, nodep->doc, intern->document);
dom_set_document_ref_pointers(child, intern->document);
}
if (child->parent != NULL){

View File

@@ -181,6 +181,8 @@ bool dom_compare_value(const xmlAttr *attr, const xmlChar *value);
void dom_attr_value_will_change(dom_object *obj, xmlAttrPtr attrp);
bool php_dom_create_nullable_object(xmlNodePtr obj, zval *return_value, dom_object *domobj);
xmlNodePtr dom_clone_node(php_dom_libxml_ns_mapper *ns_mapper, xmlNodePtr node, xmlDocPtr doc, bool recursive);
void dom_set_document_ref_pointers(xmlNodePtr node, php_libxml_ref_obj *document);
void dom_set_document_ref_pointers_attr(xmlAttrPtr attr, php_libxml_ref_obj *document);
typedef enum {
DOM_LOAD_STRING = 0,

View File

@@ -0,0 +1,19 @@
--TEST--
GH-16336 (Attribute intern document mismanagement)
--EXTENSIONS--
dom
--FILE--
<?php
$doc = new DOMDocument();
$elem = new DOMElement("g");
$attr = new DOMAttr("iF", "j");
// First append, then attribute
$doc->appendChild($elem);
$elem->setAttributeNode($attr);
echo $attr->firstChild->textContent;
?>
--EXPECT--
j

View File

@@ -0,0 +1,19 @@
--TEST--
GH-16336 (Attribute intern document mismanagement)
--EXTENSIONS--
dom
--FILE--
<?php
$doc = new DOMDocument();
$elem = new DOMElement("g");
$attr = new DOMAttr("iF", "j");
// First attribute, then append
$elem->setAttributeNode($attr);
$doc->appendChild($elem);
echo $attr->firstChild->textContent;
?>
--EXPECT--
j

View File

@@ -0,0 +1,27 @@
--TEST--
GH-16338 (Null-dereference in ext/dom/node.c)
--EXTENSIONS--
dom
--CREDITS--
chibinz
--FILE--
<?php
$ref = new DOMEntityReference("G");
$com = new DOMComment();
$doc = new DOMDocument();
$elem = new DOMElement("Rj", "o");
$com2 = new DOMComment();
$elem2 = new DOMElement("kx", null, "r");
$elem2->prepend($com);
$com->before("Z");
$com->before($com2);
$com2->after($elem);
$doc->insertBefore($elem2);
$elem->insertBefore($ref);
echo $doc->saveXML();
?>
--EXPECT--
<?xml version="1.0"?>
<kx xmlns="r">Z<Rj>o&G;</Rj></kx>