@@ -79,13 +79,13 @@ typedef struct {
7979 zend_fcall_info_cache externalEntityRefHandler ;
8080 zend_fcall_info_cache startNamespaceDeclHandler ;
8181 zend_fcall_info_cache endNamespaceDeclHandler ;
82-
8382 zval data ;
8483 zval info ;
84+
8585 int level ;
8686 int toffset ;
8787 int curtag ;
88- zval * ctag ;
88+ zend_long ctag_index ;
8989 char * * ltags ;
9090 bool lastwasopen ;
9191 bool skipwhite ;
@@ -333,6 +333,8 @@ static void xml_parser_free_obj(zend_object *object)
333333{
334334 xml_parser * parser = xml_parser_from_obj (object );
335335
336+ zval_ptr_dtor (& parser -> info );
337+ zval_ptr_dtor (& parser -> data );
336338 if (parser -> parser ) {
337339 XML_ParserFree (parser -> parser );
338340 }
@@ -425,6 +427,8 @@ static HashTable *xml_parser_get_gc(zend_object *object, zval **table, int *n)
425427 if (ZEND_FCC_INITIALIZED (parser -> endNamespaceDeclHandler )) {
426428 zend_get_gc_buffer_add_fcc (gc_buffer , & parser -> endNamespaceDeclHandler );
427429 }
430+ zend_get_gc_buffer_add_zval (gc_buffer , & parser -> data );
431+ zend_get_gc_buffer_add_zval (gc_buffer , & parser -> info );
428432
429433 zend_get_gc_buffer_use (gc_buffer , table , n );
430434
@@ -553,15 +557,18 @@ static void xml_add_to_info(xml_parser *parser, const char *name)
553557{
554558 zval * element ;
555559
556- if (Z_ISUNDEF (parser -> info )) {
560+ if (Z_ISUNDEF (parser -> info ) || UNEXPECTED ( Z_TYPE_P ( Z_REFVAL ( parser -> info )) != IS_ARRAY ) ) {
557561 return ;
558562 }
559563
564+ SEPARATE_ARRAY (Z_REFVAL (parser -> info ));
565+ zend_array * arr = Z_ARRVAL_P (Z_REFVAL (parser -> info ));
566+
560567 size_t name_len = strlen (name );
561- if ((element = zend_hash_str_find (Z_ARRVAL ( parser -> info ) , name , name_len )) == NULL ) {
568+ if ((element = zend_hash_str_find (arr , name , name_len )) == NULL ) {
562569 zval values ;
563570 array_init (& values );
564- element = zend_hash_str_update (Z_ARRVAL ( parser -> info ) , name , name_len , & values );
571+ element = zend_hash_str_update (arr , name , name_len , & values );
565572 }
566573
567574 add_next_index_long (element , parser -> curtag );
@@ -585,6 +592,28 @@ static zend_string *xml_decode_tag(xml_parser *parser, const XML_Char *tag)
585592}
586593/* }}} */
587594
595+ static zval * xml_get_separated_data (xml_parser * parser )
596+ {
597+ if (EXPECTED (Z_TYPE_P (Z_REFVAL (parser -> data )) == IS_ARRAY )) {
598+ SEPARATE_ARRAY (Z_REFVAL (parser -> data ));
599+ return Z_REFVAL (parser -> data );
600+ }
601+ return NULL ;
602+ }
603+
604+ static zval * xml_get_ctag (xml_parser * parser )
605+ {
606+ zval * data = xml_get_separated_data (parser );
607+ if (EXPECTED (data )) {
608+ zval * zv = zend_hash_index_find_deref (Z_ARRVAL_P (data ), parser -> ctag_index );
609+ if (EXPECTED (zv && Z_TYPE_P (zv ) == IS_ARRAY )) {
610+ SEPARATE_ARRAY (zv );
611+ return zv ;
612+ }
613+ }
614+ return NULL ;
615+ }
616+
588617/* {{{ xml_startElementHandler() */
589618void xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
590619{
@@ -666,7 +695,19 @@ void xml_startElementHandler(void *userData, const XML_Char *name, const XML_Cha
666695 zval_ptr_dtor (& atr );
667696 }
668697
669- parser -> ctag = zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
698+ zval * data = xml_get_separated_data (parser );
699+ if (EXPECTED (data )) {
700+ /* Note: due to array resizes or user interference,
701+ * we have to store an index instead of a zval into the array's memory. */
702+ zend_array * arr = Z_ARRVAL_P (data );
703+ if (EXPECTED (zend_hash_next_index_insert (arr , & tag ))) {
704+ parser -> ctag_index = arr -> nNextFreeElement - 1 ;
705+ } else {
706+ zval_ptr_dtor (& tag );
707+ }
708+ } else {
709+ zval_ptr_dtor (& tag );
710+ }
670711 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
671712 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
672713 }
@@ -701,17 +742,21 @@ void xml_endElementHandler(void *userData, const XML_Char *name)
701742 zval tag ;
702743
703744 if (parser -> lastwasopen ) {
704- add_assoc_string (parser -> ctag , "type" , "complete" );
745+ zval * zv = xml_get_ctag (parser );
746+ if (EXPECTED (zv )) {
747+ add_assoc_string (zv , "type" , "complete" );
748+ }
705749 } else {
706- array_init (& tag );
707-
708750 xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
709751
710- add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
711- add_assoc_string (& tag , "type" , "close" );
712- add_assoc_long (& tag , "level" , parser -> level );
713-
714- zend_hash_next_index_insert (Z_ARRVAL (parser -> data ), & tag );
752+ zval * data = xml_get_separated_data (parser );
753+ if (EXPECTED (data )) {
754+ array_init (& tag );
755+ add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
756+ add_assoc_string (& tag , "type" , "close" );
757+ add_assoc_long (& tag , "level" , parser -> level );
758+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
759+ }
715760 }
716761
717762 parser -> lastwasopen = 0 ;
@@ -770,27 +815,41 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
770815 }
771816 }
772817 if (parser -> lastwasopen ) {
818+ zval * ctag = xml_get_ctag (parser );
819+ if (UNEXPECTED (!ctag )) {
820+ zend_string_release_ex (decoded_value , false);
821+ return ;
822+ }
823+
773824 zval * myval ;
774825 /* check if the current tag already has a value - if yes append to that! */
775- if ((myval = zend_hash_find (Z_ARRVAL_P (parser -> ctag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
826+ if ((myval = zend_hash_find (Z_ARRVAL_P (ctag ), ZSTR_KNOWN (ZEND_STR_VALUE ))) && Z_TYPE_P ( myval ) == IS_STRING ) {
776827 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
777828 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
778829 strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
779830 ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
780831 zend_string_release_ex (decoded_value , 0 );
781832 } else {
782833 if (doprint || (! parser -> skipwhite )) {
783- add_assoc_str (parser -> ctag , "value" , decoded_value );
834+ add_assoc_str (ctag , "value" , decoded_value );
784835 } else {
785836 zend_string_release_ex (decoded_value , 0 );
786837 }
787838 }
788839 } else {
789840 zval tag ;
790841 zval * curtag , * mytype , * myval ;
791- ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL (parser -> data ), curtag ) {
792- if ((mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
793- if (zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
842+
843+ zval * data = xml_get_separated_data (parser );
844+ if (UNEXPECTED (!data )) {
845+ zend_string_release_ex (decoded_value , false);
846+ return ;
847+ }
848+
849+ ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL_P (data ), curtag ) {
850+ if (EXPECTED (Z_TYPE_P (curtag ) == IS_ARRAY ) && (mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
851+ if (EXPECTED (Z_TYPE_P (mytype ) == IS_STRING ) && zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
852+ SEPARATE_ARRAY (curtag );
794853 if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
795854 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
796855 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
@@ -810,7 +869,7 @@ void xml_characterDataHandler(void *userData, const XML_Char *s, int len)
810869 add_assoc_str (& tag , "value" , decoded_value );
811870 add_assoc_string (& tag , "type" , "cdata" );
812871 add_assoc_long (& tag , "level" , parser -> level );
813- zend_hash_next_index_insert (Z_ARRVAL ( parser -> data ), & tag );
872+ zend_hash_next_index_insert (Z_ARRVAL_P ( data ), & tag );
814873 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
815874 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
816875 } else {
@@ -1366,21 +1425,21 @@ PHP_FUNCTION(xml_parse_into_struct)
13661425 }
13671426
13681427 if (info ) {
1369- info = zend_try_array_init (info );
1370- if (!info ) {
1428+ if (!zend_try_array_init (info )) {
13711429 RETURN_THROWS ();
13721430 }
13731431 }
13741432
1375- xdata = zend_try_array_init (xdata );
1376- if (!xdata ) {
1433+ if (!zend_try_array_init (xdata )) {
13771434 RETURN_THROWS ();
13781435 }
13791436
1380- ZVAL_COPY_VALUE (& parser -> data , xdata );
1437+ zval_ptr_dtor (& parser -> data );
1438+ ZVAL_COPY (& parser -> data , xdata );
13811439
13821440 if (info ) {
1383- ZVAL_COPY_VALUE (& parser -> info , info );
1441+ zval_ptr_dtor (& parser -> info );
1442+ ZVAL_COPY (& parser -> info , info );
13841443 }
13851444
13861445 parser -> level = 0 ;
0 commit comments