@@ -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+ uint32_t 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 (!zv ) {
606+ return NULL ;
607+ }
608+ ZVAL_DEREF (zv );
609+ if (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,15 @@ 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 instaed of a zval into the array's memory. */
701+ parser -> ctag_index = Z_ARRVAL_P (data )-> nNextFreeElement ;
702+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
703+ } else {
704+ zval_ptr_dtor (& tag );
705+ }
666706 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
667707 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
668708 }
@@ -695,19 +735,29 @@ void _xml_endElementHandler(void *userData, const XML_Char *name)
695735
696736 if (!Z_ISUNDEF (parser -> data ) && !EG (exception )) {
697737 zval tag ;
738+ zval * data = xml_get_separated_data (parser );
698739
699740 if (parser -> lastwasopen ) {
700- add_assoc_string (parser -> ctag , "type" , "complete" );
741+ if (EXPECTED (data )) {
742+ zval * zv = zend_hash_index_find (Z_ARRVAL_P (data ), parser -> ctag_index );
743+ if (EXPECTED (zv )) {
744+ ZVAL_DEREF (zv );
745+ if (EXPECTED (Z_TYPE_P (zv ) == IS_ARRAY )) {
746+ SEPARATE_ARRAY (zv );
747+ add_assoc_string (zv , "type" , "complete" );
748+ }
749+ }
750+ }
701751 } else {
702- array_init (& tag );
703-
704752 _xml_add_to_info (parser , ZSTR_VAL (tag_name ) + parser -> toffset );
705753
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 );
754+ if (EXPECTED (data )) {
755+ array_init (& tag );
756+ add_assoc_string (& tag , "tag" , SKIP_TAGSTART (ZSTR_VAL (tag_name ))); /* cast to avoid gcc-warning */
757+ add_assoc_string (& tag , "type" , "close" );
758+ add_assoc_long (& tag , "level" , parser -> level );
759+ zend_hash_next_index_insert (Z_ARRVAL_P (data ), & tag );
760+ }
711761 }
712762
713763 parser -> lastwasopen = 0 ;
@@ -765,27 +815,39 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
765815 }
766816 }
767817 if (parser -> lastwasopen ) {
818+ zval * ctag = xml_get_ctag (parser );
819+ if (UNEXPECTED (!ctag )) {
820+ return ;
821+ }
822+
768823 zval * myval ;
769824 /* 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 )))) {
825+ if ((myval = zend_hash_find (Z_ARRVAL_P (ctag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
771826 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
772827 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
773828 strncpy (Z_STRVAL_P (myval ) + Z_STRLEN_P (myval ) - ZSTR_LEN (decoded_value ),
774829 ZSTR_VAL (decoded_value ), ZSTR_LEN (decoded_value ) + 1 );
775830 zend_string_release_ex (decoded_value , 0 );
776831 } else {
777832 if (doprint || (! parser -> skipwhite )) {
778- add_assoc_str (parser -> ctag , "value" , decoded_value );
833+ add_assoc_str (ctag , "value" , decoded_value );
779834 } else {
780835 zend_string_release_ex (decoded_value , 0 );
781836 }
782837 }
783838 } else {
784839 zval tag ;
785840 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" )) {
841+
842+ zval * data = xml_get_separated_data (parser );
843+ if (UNEXPECTED (!data )) {
844+ return ;
845+ }
846+
847+ ZEND_HASH_REVERSE_FOREACH_VAL (Z_ARRVAL_P (data ), curtag ) {
848+ if (EXPECTED (Z_TYPE_P (curtag ) == IS_ARRAY ) && (mytype = zend_hash_str_find (Z_ARRVAL_P (curtag ),"type" , sizeof ("type" ) - 1 ))) {
849+ if (EXPECTED (Z_TYPE_P (mytype ) == IS_STRING ) && zend_string_equals_literal (Z_STR_P (mytype ), "cdata" )) {
850+ SEPARATE_ARRAY (curtag );
789851 if ((myval = zend_hash_find (Z_ARRVAL_P (curtag ), ZSTR_KNOWN (ZEND_STR_VALUE )))) {
790852 size_t newlen = Z_STRLEN_P (myval ) + ZSTR_LEN (decoded_value );
791853 Z_STR_P (myval ) = zend_string_extend (Z_STR_P (myval ), newlen , 0 );
@@ -805,7 +867,7 @@ void _xml_characterDataHandler(void *userData, const XML_Char *s, int len)
805867 add_assoc_str (& tag , "value" , decoded_value );
806868 add_assoc_string (& tag , "type" , "cdata" );
807869 add_assoc_long (& tag , "level" , parser -> level );
808- zend_hash_next_index_insert (Z_ARRVAL ( parser -> data ), & tag );
870+ zend_hash_next_index_insert (Z_ARRVAL_P ( data ), & tag );
809871 } else if (parser -> level == (XML_MAXLEVEL + 1 )) {
810872 php_error_docref (NULL , E_WARNING , "Maximum depth exceeded - Results truncated" );
811873 } else {
@@ -1266,21 +1328,21 @@ PHP_FUNCTION(xml_parse_into_struct)
12661328 }
12671329
12681330 if (info ) {
1269- info = zend_try_array_init (info );
1270- if (!info ) {
1331+ if (!zend_try_array_init (info )) {
12711332 RETURN_THROWS ();
12721333 }
12731334 }
12741335
1275- xdata = zend_try_array_init (xdata );
1276- if (!xdata ) {
1336+ if (!zend_try_array_init (xdata )) {
12771337 RETURN_THROWS ();
12781338 }
12791339
1280- ZVAL_COPY_VALUE (& parser -> data , xdata );
1340+ zval_ptr_dtor (& parser -> data );
1341+ ZVAL_COPY (& parser -> data , xdata );
12811342
12821343 if (info ) {
1283- ZVAL_COPY_VALUE (& parser -> info , info );
1344+ zval_ptr_dtor (& parser -> info );
1345+ ZVAL_COPY (& parser -> info , info );
12841346 }
12851347
12861348 parser -> level = 0 ;
0 commit comments