@@ -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,28 @@ 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_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+
586613/* {{{ _xml_startElementHandler() */
587614void _xml_startElementHandler (void * userData , const XML_Char * name , const XML_Char * * attributes )
588615{
@@ -662,7 +689,19 @@ void _xml_startElementHandler(void *userData, const XML_Char *name, const XML_Ch
662689 zval_ptr_dtor (& atr );
663690 }
664691
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+ }
666705 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667706 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668707 }
@@ -697,17 +736,21 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
697736 zval tag ;
698737
699738 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+ }
701743 } else {
702- array_init (& tag );
703-
704744 _xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705745
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+ }
711754 }
712755
713756 parser -> lastwasopen = 0 ;
@@ -765,27 +808,41 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765808 }
766809 }
767810 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+
768817 zval * myval ;
769818 /* 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 ) {
771820 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772821 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773822 strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774823 ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775824 zend_string_release_ex (decoded_value , 0 );
776825 } else {
777826 if (doprint || (! parser -> skipwhite )) {
778- add_assoc_str (parser -> ctag , "value" , decoded_value );
827+ add_assoc_str (ctag , "value" , decoded_value );
779828 } else {
780829 zend_string_release_ex (decoded_value , 0 );
781830 }
782831 }
783832 } else {
784833 zval tag ;
785834 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 );
789846 if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790847 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791848 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)
805862 add_assoc_str (& tag , "value" , decoded_value );
806863 add_assoc_string (& tag , "type" , "cdata" );
807864 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 );
809866 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810867 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811868 } else {
@@ -1266,21 +1323,21 @@ PHP_FUNCTION(xml_parse_into_struct)
12661323 }
12671324
12681325 if (info ) {
1269- info = zend_try_array_init (info );
1270- if (!info ) {
1326+ if (!zend_try_array_init (info )) {
12711327 RETURN_THROWS ();
12721328 }
12731329 }
12741330
1275- xdata = zend_try_array_init (xdata );
1276- if (!xdata ) {
1331+ if (!zend_try_array_init (xdata )) {
12771332 RETURN_THROWS ();
12781333 }
12791334
1280- ZVAL_COPY_VALUE (& parser -> data , xdata );
1335+ zval_ptr_dtor (& parser -> data );
1336+ ZVAL_COPY (& parser -> data , xdata );
12811337
12821338 if (info ) {
1283- ZVAL_COPY_VALUE (& parser -> info , info );
1339+ zval_ptr_dtor (& parser -> info );
1340+ ZVAL_COPY (& parser -> info , info );
12841341 }
12851342
12861343 parser -> level = 0 ;
0 commit comments