Skip to content

Commit 082e637

Browse files
committed
Merge branch 'master' into feature/expand-rounding-target
2 parents 38c1b24 + bae3068 commit 082e637

File tree

8 files changed

+186
-15
lines changed

8 files changed

+186
-15
lines changed

ext/hash/hash.c

+10-1
Original file line numberDiff line numberDiff line change
@@ -681,7 +681,7 @@ PHP_FUNCTION(hash_init)
681681

682682
#define PHP_HASHCONTEXT_VERIFY(hash) { \
683683
if (!hash->context) { \
684-
zend_argument_type_error(1, "must be a valid Hash Context resource"); \
684+
zend_argument_type_error(1, "must be a valid, non-finalized HashContext"); \
685685
RETURN_THROWS(); \
686686
} \
687687
}
@@ -838,11 +838,15 @@ PHP_FUNCTION(hash_final)
838838
PHP_FUNCTION(hash_copy)
839839
{
840840
zval *zhash;
841+
php_hashcontext_object *context;
841842

842843
if (zend_parse_parameters(ZEND_NUM_ARGS(), "O", &zhash, php_hashcontext_ce) == FAILURE) {
843844
RETURN_THROWS();
844845
}
845846

847+
context = php_hashcontext_from_object(Z_OBJ_P(zhash));
848+
PHP_HASHCONTEXT_VERIFY(context);
849+
846850
RETVAL_OBJ(Z_OBJ_HANDLER_P(zhash, clone_obj)(Z_OBJ_P(zhash)));
847851

848852
if (php_hashcontext_from_object(Z_OBJ_P(return_value))->context == NULL) {
@@ -1395,6 +1399,11 @@ static zend_object *php_hashcontext_clone(zend_object *zobj) {
13951399
zend_object *znew = php_hashcontext_create(zobj->ce);
13961400
php_hashcontext_object *newobj = php_hashcontext_from_object(znew);
13971401

1402+
if (!oldobj->context) {
1403+
zend_throw_exception(zend_ce_value_error, "Cannot clone a finalized HashContext", 0);
1404+
return znew;
1405+
}
1406+
13981407
zend_objects_clone_members(znew, zobj);
13991408

14001409
newobj->ops = oldobj->ops;

ext/hash/tests/gh12186_1.phpt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Hash: bug #12186 - segfault in hash_copy() on a finalized context
3+
--FILE--
4+
<?php
5+
6+
$c = hash_init('sha1');
7+
hash_final($c);
8+
9+
try {
10+
hash_copy($c);
11+
} catch (Throwable $ex) {
12+
echo $ex->getMessage() . "\n";
13+
}
14+
15+
?>
16+
--EXPECTF--
17+
hash_copy(): Argument #1 ($context) must be a valid, non-finalized HashContext

ext/hash/tests/gh12186_2.phpt

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Hash: bug #12186 - segfault when cloning a finalized context
3+
--FILE--
4+
<?php
5+
6+
$c = hash_init('sha1');
7+
hash_final($c);
8+
9+
try {
10+
clone $c;
11+
} catch (Throwable $ex) {
12+
echo $ex->getMessage() . "\n";
13+
}
14+
15+
?>
16+
--EXPECTF--
17+
Cannot clone a finalized HashContext

ext/hash/tests/reuse.phpt

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,4 @@ catch (\Error $e) {
1414

1515
?>
1616
--EXPECT--
17-
hash_update(): Argument #1 ($context) must be a valid Hash Context resource
17+
hash_update(): Argument #1 ($context) must be a valid, non-finalized HashContext

ext/simplexml/simplexml.c

+36-12
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void) /* {{{ */
4444

4545
static php_sxe_object* php_sxe_object_new(zend_class_entry *ce, zend_function *fptr_count);
4646
static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data);
47+
static xmlNodePtr php_sxe_reset_iterator_no_clear_iter_data(php_sxe_object *sxe, int use_data);
4748
static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, int use_data);
4849
static void php_sxe_iterator_dtor(zend_object_iterator *iter);
4950
static int php_sxe_iterator_valid(zend_object_iterator *iter);
@@ -76,6 +77,7 @@ static void _node_as_zval(php_sxe_object *sxe, xmlNodePtr node, zval *value, SXE
7677
}
7778
/* }}} */
7879

80+
/* Important: this overwrites the iterator data, if you wish to keep it use php_sxe_get_first_node_non_destructive() instead! */
7981
static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node) /* {{{ */
8082
{
8183
if (sxe && sxe->iter.type != SXE_ITER_NONE) {
@@ -86,6 +88,15 @@ static xmlNodePtr php_sxe_get_first_node(php_sxe_object *sxe, xmlNodePtr node) /
8688
}
8789
/* }}} */
8890

91+
static xmlNodePtr php_sxe_get_first_node_non_destructive(php_sxe_object *sxe, xmlNodePtr node)
92+
{
93+
if (sxe && sxe->iter.type != SXE_ITER_NONE) {
94+
return php_sxe_reset_iterator_no_clear_iter_data(sxe, false);
95+
} else {
96+
return node;
97+
}
98+
}
99+
89100
static inline int match_ns(php_sxe_object *sxe, xmlNodePtr node, xmlChar *name, int prefix) /* {{{ */
90101
{
91102
if (name == NULL && (node->ns == NULL || node->ns->prefix == NULL)) {
@@ -979,8 +990,8 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
979990
if (sxe->iter.type == SXE_ITER_ELEMENT) {
980991
node = php_sxe_get_first_node(sxe, node);
981992
}
982-
if (!node || node->type != XML_ENTITY_DECL) {
983-
attr = node ? (xmlAttrPtr)node->properties : NULL;
993+
if (node && node->type != XML_ENTITY_DECL) {
994+
attr = node->properties;
984995
test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
985996
while (attr) {
986997
if ((!test || xmlStrEqual(attr->name, sxe->iter.name)) && match_ns(sxe, (xmlNodePtr)attr, sxe->iter.nsprefix, sxe->iter.isprefix)) {
@@ -1088,8 +1099,8 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
10881099
if (sxe->iter.type == SXE_ITER_ELEMENT) {
10891100
node = php_sxe_get_first_node(sxe, node);
10901101
}
1091-
if (!node || node->type != XML_ENTITY_DECL) {
1092-
attr = node ? (xmlAttrPtr)node->properties : NULL;
1102+
if (node && node->type != XML_ENTITY_DECL) {
1103+
attr = node->properties;
10931104
ZVAL_UNDEF(&zattr);
10941105
test = sxe->iter.name && sxe->iter.type == SXE_ITER_ATTRLIST;
10951106
while (attr) {
@@ -1163,6 +1174,12 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
11631174
sxe_properties_add(rv, name, namelen, &value);
11641175
}
11651176
next_iter:
1177+
if (UNEXPECTED(node->type == XML_ENTITY_DECL)) {
1178+
/* Entity decls are linked together via the next pointer.
1179+
* The only way to get to an entity decl is via an entity reference in the document.
1180+
* If we then continue iterating, we'll end up in the DTD. Even worse, if the entities reference each other we'll infinite loop. */
1181+
break;
1182+
}
11661183
if (use_iter) {
11671184
node = php_sxe_iterator_fetch(sxe, node->next, 0);
11681185
} else {
@@ -1598,7 +1615,7 @@ PHP_METHOD(SimpleXMLElement, getName)
15981615
sxe = Z_SXEOBJ_P(ZEND_THIS);
15991616

16001617
GET_NODE(sxe, node);
1601-
node = php_sxe_get_first_node(sxe, node);
1618+
node = php_sxe_get_first_node_non_destructive(sxe, node);
16021619
if (node) {
16031620
namelen = xmlStrlen(node->name);
16041621
RETURN_STRINGL((char*)node->name, namelen);
@@ -2425,15 +2442,9 @@ static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, i
24252442
}
24262443
/* }}} */
24272444

2428-
static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {{{ */
2445+
static xmlNodePtr php_sxe_reset_iterator_no_clear_iter_data(php_sxe_object *sxe, int use_data)
24292446
{
24302447
xmlNodePtr node;
2431-
2432-
if (!Z_ISUNDEF(sxe->iter.data)) {
2433-
zval_ptr_dtor(&sxe->iter.data);
2434-
ZVAL_UNDEF(&sxe->iter.data);
2435-
}
2436-
24372448
GET_NODE(sxe, node)
24382449

24392450
if (node) {
@@ -2446,10 +2457,23 @@ static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {
24462457
case SXE_ITER_ATTRLIST:
24472458
node = (xmlNodePtr) node->properties;
24482459
}
2460+
if (use_data) {
2461+
ZEND_ASSERT(Z_ISUNDEF(sxe->iter.data));
2462+
}
24492463
return php_sxe_iterator_fetch(sxe, node, use_data);
24502464
}
24512465
return NULL;
24522466
}
2467+
2468+
static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {{{ */
2469+
{
2470+
if (!Z_ISUNDEF(sxe->iter.data)) {
2471+
zval_ptr_dtor(&sxe->iter.data);
2472+
ZVAL_UNDEF(&sxe->iter.data);
2473+
}
2474+
2475+
return php_sxe_reset_iterator_no_clear_iter_data(sxe, use_data);
2476+
}
24532477
/* }}} */
24542478

24552479
zend_object_iterator *php_sxe_get_iterator(zend_class_entry *ce, zval *object, int by_ref) /* {{{ */

ext/simplexml/tests/gh12192.phpt

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
--TEST--
2+
GH-12192 (SimpleXML infinite loop when getName() is called within foreach)
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
8+
$xml = "<root><a>1</a><a>2</a></root>";
9+
$xml = simplexml_load_string($xml);
10+
11+
$a = $xml->a;
12+
13+
foreach ($a as $test) {
14+
echo "Iteration\n";
15+
var_dump($a->key());
16+
var_dump($a->getName());
17+
var_dump((string) $test);
18+
}
19+
20+
var_dump($a);
21+
22+
?>
23+
--EXPECT--
24+
Iteration
25+
string(1) "a"
26+
string(1) "a"
27+
string(1) "1"
28+
Iteration
29+
string(1) "a"
30+
string(1) "a"
31+
string(1) "2"
32+
object(SimpleXMLElement)#2 (2) {
33+
[0]=>
34+
string(1) "1"
35+
[1]=>
36+
string(1) "2"
37+
}

ext/simplexml/tests/gh12223.phpt

+67
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
--TEST--
2+
GH-12223: Entity reference produces infinite loop in var_dump/print_r
3+
--EXTENSIONS--
4+
simplexml
5+
--FILE--
6+
<?php
7+
8+
$xml = <<<XML
9+
<?xml version="1.0"?>
10+
<!DOCTYPE somedoc [
11+
<!ENTITY a "something">
12+
<!ENTITY b "&a;">
13+
<!ENTITY c "&b;">
14+
]>
15+
<somedoc>&c;</somedoc>
16+
XML;
17+
18+
$sxe = simplexml_load_string($xml);
19+
20+
var_dump($sxe);
21+
print_r($sxe);
22+
23+
?>
24+
--EXPECT--
25+
object(SimpleXMLElement)#1 (1) {
26+
["c"]=>
27+
object(SimpleXMLElement)#2 (1) {
28+
["c"]=>
29+
object(SimpleXMLElement)#3 (1) {
30+
["b"]=>
31+
object(SimpleXMLElement)#4 (1) {
32+
["b"]=>
33+
object(SimpleXMLElement)#5 (1) {
34+
["a"]=>
35+
object(SimpleXMLElement)#6 (1) {
36+
["a"]=>
37+
string(9) "something"
38+
}
39+
}
40+
}
41+
}
42+
}
43+
}
44+
SimpleXMLElement Object
45+
(
46+
[c] => SimpleXMLElement Object
47+
(
48+
[c] => SimpleXMLElement Object
49+
(
50+
[b] => SimpleXMLElement Object
51+
(
52+
[b] => SimpleXMLElement Object
53+
(
54+
[a] => SimpleXMLElement Object
55+
(
56+
[a] => something
57+
)
58+
59+
)
60+
61+
)
62+
63+
)
64+
65+
)
66+
67+
)

run-tests.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -4178,7 +4178,7 @@ public function getDiff(array $diffs): string
41784178
}
41794179
$next++;
41804180
}
4181-
// Found no more differenciating rows, we're done
4181+
// Found no more differentiating rows, we're done
41824182
if ($next === count($diffs)) {
41834183
if (($i - 1) < count($diffs)) {
41844184
fwrite($buffer, "--\n");

0 commit comments

Comments
 (0)