@@ -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,33 @@ 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 (Z_ARRVAL_P (data ), parser -> ctag_index );
605
+ if (UNEXPECTED (!zv )) {
606
+ return NULL ;
607
+ }
608
+ ZVAL_DEREF (zv );
609
+ if (UNEXPECTED (Z_TYPE_P (zv ) != IS_ARRAY )) {
610
+ return NULL ;
611
+ }
612
+ SEPARATE_ARRAY (zv );
613
+ return zv ;
614
+ }
615
+ return NULL ;
616
+ }
617
+
586
618
/* {{{ _xml_startElementHandler() */
587
619
void _xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
588
620
{
@@ -662,7 +694,19 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
662
694
zval_ptr_dtor (& atr );
663
695
}
664
696
665
- parser -> ctag = zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
697
+ zval * data = xml_get_separated_data (parser );
698
+ if (EXPECTED (data )) {
699
+ /* Note: due to array resizes or user interference,
700
+ * we have to store an index instead of a zval into the array's memory. */
701
+ zend_array * arr = Z_ARRVAL_P (data );
702
+ if (EXPECTED (zend_hash_next_index_insert (arr , & tag ))) {
703
+ parser -> ctag_index = arr -> nNextFreeElement - 1 ;
704
+ } else {
705
+ zval_ptr_dtor (& tag );
706
+ }
707
+ } else {
708
+ zval_ptr_dtor (& tag );
709
+ }
666
710
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667
711
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668
712
}
@@ -695,19 +739,26 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
695
739
696
740
if (!Z_ISUNDEF (parser -> data ) && !EG (exception )) {
697
741
zval tag ;
742
+ zval * data = xml_get_separated_data (parser );
698
743
699
744
if (parser -> lastwasopen ) {
700
- add_assoc_string (parser -> ctag , "type" , "complete" );
745
+ if (EXPECTED (data )) {
746
+ zval * zv = zend_hash_index_find_deref (Z_ARRVAL_P (data ), parser -> ctag_index );
747
+ if (EXPECTED (zv && Z_TYPE_P (zv ) == IS_ARRAY )) {
748
+ SEPARATE_ARRAY (zv );
749
+ add_assoc_string (zv , "type" , "complete" );
750
+ }
751
+ }
701
752
} else {
702
- array_init (& tag );
703
-
704
753
_xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705
754
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 );
755
+ if (EXPECTED (data )) {
756
+ array_init (& tag );
757
+ add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
758
+ add_assoc_string (& tag , "type" , "close" );
759
+ add_assoc_long (& tag , "level" , parser -> level );
760
+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
761
+ }
711
762
}
712
763
713
764
parser -> lastwasopen = 0 ;
@@ -765,27 +816,41 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765
816
}
766
817
}
767
818
if (parser -> lastwasopen ) {
819
+ zval * ctag = xml_get_ctag (parser );
820
+ if (UNEXPECTED (!ctag )) {
821
+ zend_string_release_ex (decoded_value , false);
822
+ return ;
823
+ }
824
+
768
825
zval * myval ;
769
826
/* 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 )))) {
827
+ if ((myval = zend_hash_find (Z_ARRVAL_P (ctag ), ZSTR_KNOWN (ZEND_STR_VALUE ))) && Z_TYPE_P ( myval ) == IS_STRING ) {
771
828
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772
829
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773
830
strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774
831
ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775
832
zend_string_release_ex (decoded_value , 0 );
776
833
} else {
777
834
if (doprint || (! parser -> skipwhite )) {
778
- add_assoc_str (parser -> ctag , "value" , decoded_value );
835
+ add_assoc_str (ctag , "value" , decoded_value );
779
836
} else {
780
837
zend_string_release_ex (decoded_value , 0 );
781
838
}
782
839
}
783
840
} else {
784
841
zval tag ;
785
842
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" )) {
843
+
844
+ zval * data = xml_get_separated_data (parser );
845
+ if (UNEXPECTED (!data )) {
846
+ zend_string_release_ex (decoded_value , false);
847
+ return ;
848
+ }
849
+
850
+ ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL_P (data ), curtag ) {
851
+ if (EXPECTED (Z_TYPE_P (curtag ) == IS_ARRAY ) && (mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
852
+ if (EXPECTED (Z_TYPE_P (mytype ) == IS_STRING ) && zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
853
+ SEPARATE_ARRAY (curtag );
789
854
if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790
855
size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791
856
Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
@@ -805,7 +870,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
805
870
add_assoc_str (& tag , "value" , decoded_value );
806
871
add_assoc_string (& tag , "type" , "cdata" );
807
872
add_assoc_long (& tag , "level" , parser -> level );
808
- zend_hash_next_index_insert (Z_ARRVAL ( parser -> data ), & tag );
873
+ zend_hash_next_index_insert (Z_ARRVAL_P ( data ), & tag );
809
874
} else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810
875
php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811
876
} else {
@@ -1266,21 +1331,21 @@ PHP_FUNCTION(xml_parse_into_struct)
1266
1331
}
1267
1332
1268
1333
if (info ) {
1269
- info = zend_try_array_init (info );
1270
- if (!info ) {
1334
+ if (!zend_try_array_init (info )) {
1271
1335
RETURN_THROWS ();
1272
1336
}
1273
1337
}
1274
1338
1275
- xdata = zend_try_array_init (xdata );
1276
- if (!xdata ) {
1339
+ if (!zend_try_array_init (xdata )) {
1277
1340
RETURN_THROWS ();
1278
1341
}
1279
1342
1280
- ZVAL_COPY_VALUE (& parser -> data , xdata );
1343
+ zval_ptr_dtor (& parser -> data );
1344
+ ZVAL_COPY (& parser -> data , xdata );
1281
1345
1282
1346
if (info ) {
1283
- ZVAL_COPY_VALUE (& parser -> info , info );
1347
+ zval_ptr_dtor (& parser -> info );
1348
+ ZVAL_COPY (& parser -> info , info );
1284
1349
}
1285
1350
1286
1351
parser -> level = 0 ;
0 commit comments