@@ -72,7 +72,7 @@ typedef struct {
72
72
/* We return a pointer to these zvals in get_gc(), so it's
73
73
* important that a) they are adjacent b) object is the first
74
74
* and c) the number of zvals is kept up to date. */
75
- #define XML_PARSER_NUM_ZVALS 12
75
+ #define XML_PARSER_NUM_ZVALS 14
76
76
zval object ;
77
77
zval startElementHandler ;
78
78
zval endElementHandler ;
@@ -85,6 +85,8 @@ typedef struct {
85
85
zval unknownEncodingHandler ;
86
86
zval startNamespaceDeclHandler ;
87
87
zval endNamespaceDeclHandler ;
88
+ zval data ;
89
+ zval info ;
88
90
89
91
zend_function * startElementPtr ;
90
92
zend_function * endElementPtr ;
@@ -98,12 +100,10 @@ typedef struct {
98
100
zend_function * startNamespaceDeclPtr ;
99
101
zend_function * endNamespaceDeclPtr ;
100
102
101
- zval data ;
102
- zval info ;
103
103
int level ;
104
104
int toffset ;
105
105
int curtag ;
106
- zval * ctag ;
106
+ zend_long ctag_index ;
107
107
char * * ltags ;
108
108
int lastwasopen ;
109
109
int skipwhite ;
@@ -326,6 +326,8 @@ static void xml_parser_free_obj(zend_object *object)
326
326
{
327
327
xml_parser * parser = xml_parser_from_obj (object );
328
328
329
+ zval_ptr_dtor (& parser -> info );
330
+ zval_ptr_dtor (& parser -> data );
329
331
if (parser -> parser ) {
330
332
XML_ParserFree (parser -> parser );
331
333
}
@@ -551,15 +553,18 @@ static void _xml_add_to_info(xml_parser *parser, const char *name)
551
553
{
552
554
zval * element ;
553
555
554
- if (Z_ISUNDEF (parser -> info )) {
556
+ if (Z_ISUNDEF (parser -> info ) || UNEXPECTED ( Z_TYPE_P ( Z_REFVAL ( parser -> info )) != IS_ARRAY ) ) {
555
557
return ;
556
558
}
557
559
560
+ SEPARATE_ARRAY (Z_REFVAL (parser -> info ));
561
+ zend_array * arr = Z_ARRVAL_P (Z_REFVAL (parser -> info ));
562
+
558
563
size_t name_len = strlen (name );
559
- if ((element = zend_hash_str_find (Z_ARRVAL ( parser -> info ) , name , name_len )) == NULL ) {
564
+ if ((element = zend_hash_str_find (arr , name , name_len )) == NULL ) {
560
565
zval values ;
561
566
array_init (& values );
562
- element = zend_hash_str_update (Z_ARRVAL ( parser -> info ) , name , name_len , & values );
567
+ element = zend_hash_str_update (arr , name , name_len , & values );
563
568
}
564
569
565
570
add_next_index_long (element , parser -> curtag );
@@ -583,6 +588,28 @@ static zend_string *_xml_decode_tag(xml_parser *parser, const XML_Char *tag)
583
588
}
584
589
/* }}} */
585
590
591
+ static zval * xml_get_separated_data (xml_parser * parser )
592
+ {
593
+ if (EXPECTED (Z_TYPE_P (Z_REFVAL (parser -> data )) == IS_ARRAY )) {
594
+ SEPARATE_ARRAY (Z_REFVAL (parser -> data ));
595
+ return Z_REFVAL (parser -> data );
596
+ }
597
+ return NULL ;
598
+ }
599
+
600
+ static zval * xml_get_ctag (xml_parser * parser )
601
+ {
602
+ zval * data = xml_get_separated_data (parser );
603
+ if (EXPECTED (data )) {
604
+ zval * zv = zend_hash_index_find_deref (Z_ARRVAL_P (data ), parser -> ctag_index );
605
+ if (EXPECTED (zv && Z_TYPE_P (zv ) == IS_ARRAY )) {
606
+ SEPARATE_ARRAY (zv );
607
+ return zv ;
608
+ }
609
+ }
610
+ return NULL ;
611
+ }
612
+
586
613
/* {{{ _xml_startElementHandler() */
587
614
void _xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
588
615
{
@@ -662,7 +689,19 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
662
689
zval_ptr_dtor (& atr );
663
690
}
664
691
665
- parser -> ctag = zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
692
+ zval * data = xml_get_separated_data (parser );
693
+ if (EXPECTED (data )) {
694
+ /* Note: due to array resizes or user interference,
695
+ * we have to store an index instead of a zval into the array's memory. */
696
+ zend_array * arr = Z_ARRVAL_P (data );
697
+ if (EXPECTED (zend_hash_next_index_insert (arr , & tag ))) {
698
+ parser -> ctag_index = arr -> nNextFreeElement - 1 ;
699
+ } else {
700
+ zval_ptr_dtor (& tag );
701
+ }
702
+ } else {
703
+ zval_ptr_dtor (& tag );
704
+ }
666
705
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667
706
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668
707
}
@@ -697,17 +736,21 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
697
736
zval tag ;
698
737
699
738
if (parser -> lastwasopen ) {
700
- add_assoc_string (parser -> ctag , "type" , "complete" );
739
+ zval * zv = xml_get_ctag (parser );
740
+ if (EXPECTED (zv )) {
741
+ add_assoc_string (zv , "type" , "complete" );
742
+ }
701
743
} else {
702
- array_init (& tag );
703
-
704
744
_xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705
745
706
- add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
707
- add_assoc_string (& tag , "type" , "close" );
708
- add_assoc_long (& tag , "level" , parser -> level );
709
-
710
- zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
746
+ zval * data = xml_get_separated_data (parser );
747
+ if (EXPECTED (data )) {
748
+ array_init (& tag );
749
+ add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
750
+ add_assoc_string (& tag , "type" , "close" );
751
+ add_assoc_long (& tag , "level" , parser -> level );
752
+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
753
+ }
711
754
}
712
755
713
756
parser -> lastwasopen = 0 ;
@@ -765,27 +808,41 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765
808
}
766
809
}
767
810
if (parser -> lastwasopen ) {
811
+ zval * ctag = xml_get_ctag (parser );
812
+ if (UNEXPECTED (!ctag )) {
813
+ zend_string_release_ex (decoded_value , false);
814
+ return ;
815
+ }
816
+
768
817
zval * myval ;
769
818
/* check if the current tag already has a value - if yes append to that! */
770
- if ((myval = zend_hash_find (Z_ARRVAL_P (parser -> ctag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
819
+ if ((myval = zend_hash_find (Z_ARRVAL_P (ctag ), ZSTR_KNOWN (ZEND_STR_VALUE ))) && Z_TYPE_P ( myval ) == IS_STRING ) {
771
820
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772
821
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773
822
strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774
823
ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775
824
zend_string_release_ex (decoded_value , 0 );
776
825
} else {
777
826
if (doprint || (! parser -> skipwhite )) {
778
- add_assoc_str (parser -> ctag , "value" , decoded_value );
827
+ add_assoc_str (ctag , "value" , decoded_value );
779
828
} else {
780
829
zend_string_release_ex (decoded_value , 0 );
781
830
}
782
831
}
783
832
} else {
784
833
zval tag ;
785
834
zval * curtag , * mytype , * myval ;
786
- ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL (parser -> data ), curtag ) {
787
- if ((mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
788
- if (zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
835
+
836
+ zval * data = xml_get_separated_data (parser );
837
+ if (UNEXPECTED (!data )) {
838
+ zend_string_release_ex (decoded_value , false);
839
+ return ;
840
+ }
841
+
842
+ ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL_P (data ), curtag ) {
843
+ if (EXPECTED (Z_TYPE_P (curtag ) == IS_ARRAY ) && (mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
844
+ if (EXPECTED (Z_TYPE_P (mytype ) == IS_STRING ) && zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
845
+ SEPARATE_ARRAY (curtag );
789
846
if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790
847
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791
848
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
@@ -805,7 +862,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
805
862
add_assoc_str (& tag , "value" , decoded_value );
806
863
add_assoc_string (& tag , "type" , "cdata" );
807
864
add_assoc_long (& tag , "level" , parser -> level );
808
- zend_hash_next_index_insert (Z_ARRVAL ( parser -> data ), & tag );
865
+ zend_hash_next_index_insert (Z_ARRVAL_P ( data ), & tag );
809
866
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810
867
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811
868
} else {
@@ -1266,21 +1323,21 @@ PHP_FUNCTION(xml_parse_into_struct)
1266
1323
}
1267
1324
1268
1325
if (info ) {
1269
- info = zend_try_array_init (info );
1270
- if (!info ) {
1326
+ if (!zend_try_array_init (info )) {
1271
1327
RETURN_THROWS ();
1272
1328
}
1273
1329
}
1274
1330
1275
- xdata = zend_try_array_init (xdata );
1276
- if (!xdata ) {
1331
+ if (!zend_try_array_init (xdata )) {
1277
1332
RETURN_THROWS ();
1278
1333
}
1279
1334
1280
- ZVAL_COPY_VALUE (& parser -> data , xdata );
1335
+ zval_ptr_dtor (& parser -> data );
1336
+ ZVAL_COPY (& parser -> data , xdata );
1281
1337
1282
1338
if (info ) {
1283
- ZVAL_COPY_VALUE (& parser -> info , info );
1339
+ zval_ptr_dtor (& parser -> info );
1340
+ ZVAL_COPY (& parser -> info , info );
1284
1341
}
1285
1342
1286
1343
parser -> level = 0 ;
0 commit comments