Merge branch 'PHP-8.2' into PHP-8.3

* PHP-8.2:
  Apply SimpleXML iterator fixes only on master
This commit is contained in:
Niels Dossche 2023-09-30 17:55:34 +02:00
commit ec2ef6465d
6 changed files with 36 additions and 188 deletions

3
NEWS
View file

@ -17,6 +17,9 @@ PHP NEWS
. Fixed bug GH-12297 (PHP Startup: Invalid library (maybe not a PHP library) . Fixed bug GH-12297 (PHP Startup: Invalid library (maybe not a PHP library)
'mysqlnd.so' in Unknown on line). (nielsdos) 'mysqlnd.so' in Unknown on line). (nielsdos)
- SimpleXML:
. Apply iterator fixes only on master. (nielsdos)
- XSL: - XSL:
. Fix type error on XSLTProcessor::transformToDoc return value with . Fix type error on XSLTProcessor::transformToDoc return value with
SimpleXML. (nielsdos) SimpleXML. (nielsdos)

View file

@ -77,10 +77,10 @@ static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE
} }
/* }}} */ /* }}} */
static xmlNodePtr php_sxe_get_first_node_non_destructive(php_sxe_object *sxe, xmlNodePtr node) static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node)
{ {
if (sxe && sxe->iter.type != SXE_ITER_NONE) { if (sxe && sxe->iter.type != SXE_ITER_NONE) {
return php_sxe_reset_iterator_no_clear_iter_data(sxe, false); return php_sxe_reset_iterator(sxe, 1);
} else { } else {
return node; return node;
} }
@ -163,7 +163,7 @@ static xmlNodePtr sxe_get_element_by_name(php_sxe_object *sxe, xmlNodePtr node,
if (sxe->iter.type == SXE_ITER_NONE) { if (sxe->iter.type == SXE_ITER_NONE) {
sxe->iter.type = SXE_ITER_CHILD; sxe->iter.type = SXE_ITER_CHILD;
} }
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
sxe->iter.type = orgtype; sxe->iter.type = orgtype;
} }
@ -238,11 +238,11 @@ long_dim:
if (sxe->iter.type == SXE_ITER_ATTRLIST) { if (sxe->iter.type == SXE_ITER_ATTRLIST) {
attribs = 1; attribs = 1;
elements = 0; elements = 0;
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = (xmlAttrPtr)node; attr = (xmlAttrPtr)node;
test = sxe->iter.name != NULL; test = sxe->iter.name != NULL;
} else if (sxe->iter.type != SXE_ITER_CHILD) { } else if (sxe->iter.type != SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = node ? node->properties : NULL; attr = node ? node->properties : NULL;
test = 0; test = 0;
if (!member && node && node->parent && if (!member && node && node->parent &&
@ -290,7 +290,7 @@ long_dim:
xmlNodePtr mynode = node; xmlNodePtr mynode = node;
if (sxe->iter.type == SXE_ITER_CHILD) { if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
if (sxe->iter.type == SXE_ITER_NONE) { if (sxe->iter.type == SXE_ITER_NONE) {
if (member && Z_LVAL_P(member) > 0) { if (member && Z_LVAL_P(member) > 0) {
@ -426,12 +426,12 @@ long_dim:
if (sxe->iter.type == SXE_ITER_ATTRLIST) { if (sxe->iter.type == SXE_ITER_ATTRLIST) {
attribs = 1; attribs = 1;
elements = 0; elements = 0;
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = (xmlAttrPtr)node; attr = (xmlAttrPtr)node;
test = sxe->iter.name != NULL; test = sxe->iter.name != NULL;
} else if (sxe->iter.type != SXE_ITER_CHILD) { } else if (sxe->iter.type != SXE_ITER_CHILD) {
mynode = node; mynode = node;
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = node ? node->properties : NULL; attr = node ? node->properties : NULL;
test = 0; test = 0;
if (!member && node && node->parent && if (!member && node && node->parent &&
@ -677,7 +677,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
attribs = 0; attribs = 0;
elements = 1; elements = 1;
if (sxe->iter.type == SXE_ITER_CHILD) { if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
} }
} }
@ -685,11 +685,11 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
if (sxe->iter.type == SXE_ITER_ATTRLIST) { if (sxe->iter.type == SXE_ITER_ATTRLIST) {
attribs = 1; attribs = 1;
elements = 0; elements = 0;
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = (xmlAttrPtr)node; attr = (xmlAttrPtr)node;
test = sxe->iter.name != NULL; test = sxe->iter.name != NULL;
} else if (sxe->iter.type != SXE_ITER_CHILD) { } else if (sxe->iter.type != SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = node ? node->properties : NULL; attr = node ? node->properties : NULL;
test = 0; test = 0;
} }
@ -729,7 +729,7 @@ static int sxe_prop_dim_exists(zend_object *object, zval *member, int check_empt
if (elements) { if (elements) {
if (Z_TYPE_P(member) == IS_LONG) { if (Z_TYPE_P(member) == IS_LONG) {
if (sxe->iter.type == SXE_ITER_CHILD) { if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
} else { } else {
@ -801,7 +801,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
attribs = 0; attribs = 0;
elements = 1; elements = 1;
if (sxe->iter.type == SXE_ITER_CHILD) { if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
} }
} }
@ -809,11 +809,11 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
if (sxe->iter.type == SXE_ITER_ATTRLIST) { if (sxe->iter.type == SXE_ITER_ATTRLIST) {
attribs = 1; attribs = 1;
elements = 0; elements = 0;
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = (xmlAttrPtr)node; attr = (xmlAttrPtr)node;
test = sxe->iter.name != NULL; test = sxe->iter.name != NULL;
} else if (sxe->iter.type != SXE_ITER_CHILD) { } else if (sxe->iter.type != SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
attr = node ? node->properties : NULL; attr = node ? node->properties : NULL;
test = 0; test = 0;
} }
@ -850,7 +850,7 @@ static void sxe_prop_dim_delete(zend_object *object, zval *member, bool elements
if (elements) { if (elements) {
if (Z_TYPE_P(member) == IS_LONG) { if (Z_TYPE_P(member) == IS_LONG) {
if (sxe->iter.type == SXE_ITER_CHILD) { if (sxe->iter.type == SXE_ITER_CHILD) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL); node = sxe_get_element_by_offset(sxe, Z_LVAL_P(member), node, NULL);
if (node) { if (node) {
@ -983,7 +983,7 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
} }
if (sxe->iter.type == SXE_ITER_ELEMENT) { if (sxe->iter.type == SXE_ITER_ELEMENT) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
if (!node || node->type != XML_ENTITY_DECL) { if (!node || node->type != XML_ENTITY_DECL) {
attr = node ? (xmlAttrPtr)node->properties : NULL; attr = node ? (xmlAttrPtr)node->properties : NULL;
@ -997,7 +997,7 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
} }
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
is_empty = 1; is_empty = 1;
ZVAL_UNDEF(&iter_data); ZVAL_UNDEF(&iter_data);
if (node && sxe->iter.type != SXE_ITER_ATTRLIST) { if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
@ -1092,7 +1092,7 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
} }
if (is_debug || sxe->iter.type != SXE_ITER_CHILD) { if (is_debug || sxe->iter.type != SXE_ITER_CHILD) {
if (sxe->iter.type == SXE_ITER_ELEMENT) { if (sxe->iter.type == SXE_ITER_ELEMENT) {
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
} }
if (!node || node->type != XML_ENTITY_DECL) { if (!node || node->type != XML_ENTITY_DECL) {
attr = node ? (xmlAttrPtr)node->properties : NULL; attr = node ? (xmlAttrPtr)node->properties : NULL;
@ -1114,7 +1114,7 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
} }
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (node && sxe->iter.type != SXE_ITER_ATTRLIST) { if (node && sxe->iter.type != SXE_ITER_ATTRLIST) {
if (node->type == XML_ATTRIBUTE_NODE) { if (node->type == XML_ATTRIBUTE_NODE) {
@ -1273,7 +1273,7 @@ PHP_METHOD(SimpleXMLElement, xpath)
} }
GET_NODE(sxe, nodeptr); GET_NODE(sxe, nodeptr);
nodeptr = php_sxe_get_first_node_non_destructive(sxe, nodeptr); nodeptr = php_sxe_get_first_node(sxe, nodeptr);
if (!nodeptr) { if (!nodeptr) {
return; return;
} }
@ -1382,7 +1382,7 @@ PHP_METHOD(SimpleXMLElement, asXML)
sxe = Z_SXEOBJ_P(ZEND_THIS); sxe = Z_SXEOBJ_P(ZEND_THIS);
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (!node) { if (!node) {
RETURN_FALSE; RETURN_FALSE;
@ -1505,7 +1505,7 @@ PHP_METHOD(SimpleXMLElement, getNamespaces)
sxe = Z_SXEOBJ_P(ZEND_THIS); sxe = Z_SXEOBJ_P(ZEND_THIS);
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (node) { if (node) {
if (node->type == XML_ELEMENT_NODE) { if (node->type == XML_ELEMENT_NODE) {
@ -1590,7 +1590,7 @@ PHP_METHOD(SimpleXMLElement, children)
} }
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (!node) { if (!node) {
return; return;
} }
@ -1614,7 +1614,7 @@ PHP_METHOD(SimpleXMLElement, getName)
sxe = Z_SXEOBJ_P(ZEND_THIS); sxe = Z_SXEOBJ_P(ZEND_THIS);
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (node) { if (node) {
namelen = xmlStrlen(node->name); namelen = xmlStrlen(node->name);
RETURN_STRINGL((char*)node->name, namelen); RETURN_STRINGL((char*)node->name, namelen);
@ -1639,7 +1639,7 @@ PHP_METHOD(SimpleXMLElement, attributes)
sxe = Z_SXEOBJ_P(ZEND_THIS); sxe = Z_SXEOBJ_P(ZEND_THIS);
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (!node) { if (!node) {
return; return;
} }
@ -1682,7 +1682,7 @@ PHP_METHOD(SimpleXMLElement, addChild)
return; return;
} }
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (node == NULL) { if (node == NULL) {
php_error_docref(NULL, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree"); php_error_docref(NULL, E_WARNING, "Cannot add child. Parent is not a permanent member of the XML tree");
@ -1742,7 +1742,7 @@ PHP_METHOD(SimpleXMLElement, addAttribute)
sxe = Z_SXEOBJ_P(ZEND_THIS); sxe = Z_SXEOBJ_P(ZEND_THIS);
GET_NODE(sxe, node); GET_NODE(sxe, node);
node = php_sxe_get_first_node_non_destructive(sxe, node); node = php_sxe_get_first_node(sxe, node);
if (node && node->type != XML_ELEMENT_NODE) { if (node && node->type != XML_ELEMENT_NODE) {
node = node->parent; node = node->parent;
@ -1835,7 +1835,7 @@ static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int
sxe = php_sxe_fetch_object(readobj); sxe = php_sxe_fetch_object(readobj);
if (type == _IS_BOOL) { if (type == _IS_BOOL) {
node = php_sxe_get_first_node_non_destructive(sxe, NULL); node = php_sxe_get_first_node(sxe, NULL);
if (node) { if (node) {
ZVAL_TRUE(writeobj); ZVAL_TRUE(writeobj);
} else { } else {
@ -1845,7 +1845,7 @@ static zend_result sxe_object_cast_ex(zend_object *readobj, zval *writeobj, int
} }
if (sxe->iter.type != SXE_ITER_NONE) { if (sxe->iter.type != SXE_ITER_NONE) {
node = php_sxe_get_first_node_non_destructive(sxe, NULL); node = php_sxe_get_first_node(sxe, NULL);
if (node) { if (node) {
contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1); contents = xmlNodeListGetString((xmlDocPtr) sxe->document->ptr, node->children, 1);
} }
@ -2593,7 +2593,7 @@ void *simplexml_export_node(zval *object) /* {{{ */
sxe = Z_SXEOBJ_P(object); sxe = Z_SXEOBJ_P(object);
GET_NODE(sxe, node); GET_NODE(sxe, node);
return php_sxe_get_first_node_non_destructive(sxe, node); return php_sxe_get_first_node(sxe, node);
} }
/* }}} */ /* }}} */

View file

@ -1,92 +0,0 @@
--TEST--
Bug #55098 (SimpleXML iteration produces infinite loop)
--EXTENSIONS--
simplexml
--FILE--
<?php
$xmlString = "<root><a><b>1</b><b>2</b><b>3</b></a></root>";
$xml = simplexml_load_string($xmlString);
$nodes = $xml->a->b;
function test($nodes, $name, $callable) {
echo "--- $name ---\n";
foreach ($nodes as $nodeData) {
echo "nodeData: " . $nodeData . "\n";
$callable($nodes);
}
}
test($nodes, "asXml", fn ($n) => $n->asXml());
test($nodes, "attributes", fn ($n) => $n->attributes());
test($nodes, "children", fn ($n) => $n->children());
test($nodes, "getNamespaces", fn ($n) => $n->getNamespaces());
test($nodes, "xpath", fn ($n) => $n->xpath("/root/a/b"));
test($nodes, "var_dump", fn ($n) => var_dump($n));
test($nodes, "manipulation combined with querying", function ($n) {
$n->addAttribute("attr", "value");
(bool) $n["attr"];
$n->addChild("child", "value");
$n->outer[]->inner = "foo";
(bool) $n->outer;
(bool) $n;
isset($n->outer);
isset($n["attr"]);
unset($n->outer);
unset($n["attr"]);
unset($n->child);
});
?>
--EXPECT--
--- asXml ---
nodeData: 1
nodeData: 2
nodeData: 3
--- attributes ---
nodeData: 1
nodeData: 2
nodeData: 3
--- children ---
nodeData: 1
nodeData: 2
nodeData: 3
--- getNamespaces ---
nodeData: 1
nodeData: 2
nodeData: 3
--- xpath ---
nodeData: 1
nodeData: 2
nodeData: 3
--- var_dump ---
nodeData: 1
object(SimpleXMLElement)#3 (3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
nodeData: 2
object(SimpleXMLElement)#3 (3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
nodeData: 3
object(SimpleXMLElement)#3 (3) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
[2]=>
string(1) "3"
}
--- manipulation combined with querying ---
nodeData: 1
nodeData: 2
nodeData: 3

View file

@ -41,7 +41,7 @@ foreach ($a2->b->c->children() as $key => $value) {
var_dump($value); var_dump($value);
}?> }?>
--EXPECT-- --EXPECT--
object(A)#4 (2) { object(A)#2 (2) {
["@attributes"]=> ["@attributes"]=>
array(1) { array(1) {
["attr"]=> ["attr"]=>
@ -50,7 +50,7 @@ object(A)#4 (2) {
[0]=> [0]=>
string(10) "Some Value" string(10) "Some Value"
} }
object(A)#6 (2) { object(A)#3 (2) {
["@attributes"]=> ["@attributes"]=>
array(1) { array(1) {
["attr"]=> ["attr"]=>

View file

@ -1,37 +0,0 @@
--TEST--
GH-12192 (SimpleXML infinite loop when getName() is called within foreach)
--EXTENSIONS--
simplexml
--FILE--
<?php
$xml = "<root><a>1</a><a>2</a></root>";
$xml = simplexml_load_string($xml);
$a = $xml->a;
foreach ($a as $test) {
echo "Iteration\n";
var_dump($a->key());
var_dump($a->getName());
var_dump((string) $test);
}
var_dump($a);
?>
--EXPECT--
Iteration
string(1) "a"
string(1) "a"
string(1) "1"
Iteration
string(1) "a"
string(1) "a"
string(1) "2"
object(SimpleXMLElement)#2 (2) {
[0]=>
string(1) "1"
[1]=>
string(1) "2"
}

View file

@ -1,26 +0,0 @@
--TEST--
GH-12208 (SimpleXML infinite loop when a cast is used inside a foreach)
--EXTENSIONS--
simplexml
--FILE--
<?php
$xml = "<root><a>1</a><a>2</a></root>";
$xml = simplexml_load_string($xml);
$a = $xml->a;
foreach ($a as $test) {
var_dump((string) $a->current());
var_dump((string) $a);
var_dump((bool) $a);
}
?>
--EXPECT--
string(1) "1"
string(1) "1"
bool(true)
string(1) "2"
string(1) "1"
bool(true)