@@ -44,6 +44,7 @@ PHP_SXE_API zend_class_entry *sxe_get_element_class_entry(void) /* {{{ */
44
44
45
45
static php_sxe_object * php_sxe_object_new (zend_class_entry * ce , zend_function * fptr_count );
46
46
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 );
47
48
static xmlNodePtr php_sxe_iterator_fetch (php_sxe_object * sxe , xmlNodePtr node , int use_data );
48
49
static void php_sxe_iterator_dtor (zend_object_iterator * iter );
49
50
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
76
77
}
77
78
/* }}} */
78
79
80
+ /* Important: this overwrites the iterator data, if you wish to keep it use php_sxe_get_first_node_non_destructive() instead! */
79
81
static xmlNodePtr php_sxe_get_first_node (php_sxe_object * sxe , xmlNodePtr node ) /* {{{ */
80
82
{
81
83
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) /
86
88
}
87
89
/* }}} */
88
90
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
+
89
100
static inline int match_ns (php_sxe_object * sxe , xmlNodePtr node , xmlChar * name , int prefix ) /* {{{ */
90
101
{
91
102
if (name == NULL && (node -> ns == NULL || node -> ns -> prefix == NULL )) {
@@ -979,8 +990,8 @@ static int sxe_prop_is_empty(zend_object *object) /* {{{ */
979
990
if (sxe -> iter .type == SXE_ITER_ELEMENT ) {
980
991
node = php_sxe_get_first_node (sxe , node );
981
992
}
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 ;
984
995
test = sxe -> iter .name && sxe -> iter .type == SXE_ITER_ATTRLIST ;
985
996
while (attr ) {
986
997
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) /* {{{ */
1088
1099
if (sxe -> iter .type == SXE_ITER_ELEMENT ) {
1089
1100
node = php_sxe_get_first_node (sxe , node );
1090
1101
}
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 ;
1093
1104
ZVAL_UNDEF (& zattr );
1094
1105
test = sxe -> iter .name && sxe -> iter .type == SXE_ITER_ATTRLIST ;
1095
1106
while (attr ) {
@@ -1163,6 +1174,12 @@ static HashTable *sxe_get_prop_hash(zend_object *object, int is_debug) /* {{{ */
1163
1174
sxe_properties_add (rv , name , namelen , & value );
1164
1175
}
1165
1176
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
+ }
1166
1183
if (use_iter ) {
1167
1184
node = php_sxe_iterator_fetch (sxe , node -> next , 0 );
1168
1185
} else {
@@ -1598,7 +1615,7 @@ PHP_METHOD(SimpleXMLElement, getName)
1598
1615
sxe = Z_SXEOBJ_P (ZEND_THIS );
1599
1616
1600
1617
GET_NODE (sxe , node );
1601
- node = php_sxe_get_first_node (sxe , node );
1618
+ node = php_sxe_get_first_node_non_destructive (sxe , node );
1602
1619
if (node ) {
1603
1620
namelen = xmlStrlen (node -> name );
1604
1621
RETURN_STRINGL ((char * )node -> name , namelen );
@@ -2425,15 +2442,9 @@ static xmlNodePtr php_sxe_iterator_fetch(php_sxe_object *sxe, xmlNodePtr node, i
2425
2442
}
2426
2443
/* }}} */
2427
2444
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 )
2429
2446
{
2430
2447
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
-
2437
2448
GET_NODE (sxe , node )
2438
2449
2439
2450
if (node ) {
@@ -2446,10 +2457,23 @@ static xmlNodePtr php_sxe_reset_iterator(php_sxe_object *sxe, int use_data) /* {
2446
2457
case SXE_ITER_ATTRLIST :
2447
2458
node = (xmlNodePtr ) node -> properties ;
2448
2459
}
2460
+ if (use_data ) {
2461
+ ZEND_ASSERT (Z_ISUNDEF (sxe -> iter .data ));
2462
+ }
2449
2463
return php_sxe_iterator_fetch (sxe , node , use_data );
2450
2464
}
2451
2465
return NULL ;
2452
2466
}
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
+ }
2453
2477
/* }}} */
2454
2478
2455
2479
zend_object_iterator * php_sxe_get_iterator (zend_class_entry * ce , zval * object , int by_ref ) /* {{{ */
0 commit comments