@@ -72,7 +72,7 @@ typedef struct {
7272 /* We return a pointer to these zvals in get_gc(), so it's
7373 * important that a) they are adjacent b) object is the first
7474 * 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
7676 zval object ;
7777 zval startElementHandler ;
7878 zval endElementHandler ;
@@ -85,6 +85,8 @@ typedef struct {
8585 zval unknownEncodingHandler ;
8686 zval startNamespaceDeclHandler ;
8787 zval endNamespaceDeclHandler ;
88+ zval data ;
89+ zval info ;
8890
8991 zend_function * startElementPtr ;
9092 zend_function * endElementPtr ;
@@ -98,12 +100,10 @@ typedef struct {
98100 zend_function * startNamespaceDeclPtr ;
99101 zend_function * endNamespaceDeclPtr ;
100102
101- zval data ;
102- zval info ;
103103 int level ;
104104 int toffset ;
105105 int curtag ;
106- zval * ctag ;
106+ zend_long ctag_index ;
107107 char * * ltags ;
108108 int lastwasopen ;
109109 int skipwhite ;
@@ -326,6 +326,8 @@ static void xml_parser_free_obj(zend_object *object)
326326{
327327 xml_parser * parser = xml_parser_from_obj (object );
328328
329+ zval_ptr_dtor (& parser -> info );
330+ zval_ptr_dtor (& parser -> data );
329331 if (parser -> parser ) {
330332 XML_ParserFree (parser -> parser );
331333 }
@@ -551,15 +553,18 @@ static void _xml_add_to_info(xml_parser *parser, const char *name)
551553{
552554 zval * element ;
553555
554- if (Z_ISUNDEF (parser -> info )) {
556+ if (Z_ISUNDEF (parser -> info ) || UNEXPECTED ( Z_TYPE_P ( Z_REFVAL ( parser -> info )) != IS_ARRAY ) ) {
555557 return ;
556558 }
557559
560+ SEPARATE_ARRAY (Z_REFVAL (parser -> info ));
561+ zend_array * arr = Z_ARRVAL_P (Z_REFVAL (parser -> info ));
562+
558563 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 ) {
560565 zval values ;
561566 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 );
563568 }
564569
565570 add_next_index_long (element , parser -> curtag );
@@ -583,6 +588,33 @@ static zend_string *_xml_decode_tag(xml_parser *parser, const XML_Char *tag)
583588}
584589/* }}} */
585590
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+
586618/* {{{ _xml_startElementHandler() */
587619void _xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
588620{
@@ -662,7 +694,19 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
662694 zval_ptr_dtor (& atr );
663695 }
664696
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+ }
666710 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667711 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668712 }
@@ -695,19 +739,26 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
695739
696740 if (!Z_ISUNDEF (parser -> data ) && !EG (exception )) {
697741 zval tag ;
742+ zval * data = xml_get_separated_data (parser );
698743
699744 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+ }
701752 } else {
702- array_init (& tag );
703-
704753 _xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705754
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+ }
711762 }
712763
713764 parser -> lastwasopen = 0 ;
@@ -765,27 +816,41 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765816 }
766817 }
767818 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+
768825 zval * myval ;
769826 /* 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 ) {
771828 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772829 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773830 strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774831 ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775832 zend_string_release_ex (decoded_value , 0 );
776833 } else {
777834 if (doprint || (! parser -> skipwhite )) {
778- add_assoc_str (parser -> ctag , "value" , decoded_value );
835+ add_assoc_str (ctag , "value" , decoded_value );
779836 } else {
780837 zend_string_release_ex (decoded_value , 0 );
781838 }
782839 }
783840 } else {
784841 zval tag ;
785842 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 );
789854 if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790855 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791856 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)
805870 add_assoc_str (& tag , "value" , decoded_value );
806871 add_assoc_string (& tag , "type" , "cdata" );
807872 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 );
809874 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810875 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811876 } else {
@@ -1266,21 +1331,21 @@ PHP_FUNCTION(xml_parse_into_struct)
12661331 }
12671332
12681333 if (info ) {
1269- info = zend_try_array_init (info );
1270- if (!info ) {
1334+ if (!zend_try_array_init (info )) {
12711335 RETURN_THROWS ();
12721336 }
12731337 }
12741338
1275- xdata = zend_try_array_init (xdata );
1276- if (!xdata ) {
1339+ if (!zend_try_array_init (xdata )) {
12771340 RETURN_THROWS ();
12781341 }
12791342
1280- ZVAL_COPY_VALUE (& parser -> data , xdata );
1343+ zval_ptr_dtor (& parser -> data );
1344+ ZVAL_COPY (& parser -> data , xdata );
12811345
12821346 if (info ) {
1283- ZVAL_COPY_VALUE (& parser -> info , info );
1347+ zval_ptr_dtor (& parser -> info );
1348+ ZVAL_COPY (& parser -> info , info );
12841349 }
12851350
12861351 parser -> level = 0 ;
0 commit comments