@@ -764,112 +764,140 @@ static int php_var_serialize_call_magic_serialize(zval *retval, zval *obj) /* {{
764764}
765765/* }}} */
766766
767- static void php_var_serialize_collect_names (HashTable * ht , HashTable * src ) /* {{{ */
767+ static int php_var_serialize_try_add_sleep_prop (
768+ HashTable * ht , HashTable * props , zend_string * name , zend_string * error_name ) /* {{{ */
768769{
769- zval * val ;
770- zend_string * name , * tmp_name ;
770+ zval * val = zend_hash_find (props , name );
771+ if (val == NULL ) {
772+ return FAILURE ;
773+ }
771774
772- zend_hash_init (ht , zend_hash_num_elements (src ), NULL , NULL , 0 );
773- ZEND_HASH_FOREACH_VAL (src , val ) {
774- if (Z_TYPE_P (val ) != IS_STRING ) {
775- php_error_docref (NULL , E_NOTICE ,
776- "__sleep should return an array only containing the names of instance-variables to serialize." );
775+ if (Z_TYPE_P (val ) == IS_INDIRECT ) {
776+ val = Z_INDIRECT_P (val );
777+ if (Z_TYPE_P (val ) == IS_UNDEF ) {
778+ return FAILURE ;
777779 }
780+ }
778781
779- name = zval_get_tmp_string (val , & tmp_name );
780- if (zend_hash_exists (ht , name )) {
781- php_error_docref (NULL , E_NOTICE ,
782- "\"%s\" is returned from __sleep multiple times" , ZSTR_VAL (name ));
783- zend_tmp_string_release (tmp_name );
784- continue ;
785- }
786- zend_hash_add_empty_element (ht , name );
787- zend_tmp_string_release (tmp_name );
788- } ZEND_HASH_FOREACH_END ();
782+ if (!zend_hash_add (ht , name , val )) {
783+ php_error_docref (NULL , E_NOTICE ,
784+ "\"%s\" is returned from __sleep multiple times" , ZSTR_VAL (error_name ));
785+ return SUCCESS ;
786+ }
787+
788+ Z_TRY_ADDREF_P (val );
789+ return SUCCESS ;
789790}
790791/* }}} */
791792
792- static void php_var_serialize_class (smart_str * buf , zval * struc , zval * retval_ptr , php_serialize_data_t var_hash ) /* {{{ */
793+ static void php_var_serialize_get_sleep_props (
794+ HashTable * ht , zval * struc , HashTable * sleep_retval ) /* {{{ */
793795{
794796 zend_class_entry * ce = Z_OBJCE_P (struc );
795- HashTable names , * propers ;
796- zval nval ;
797- zend_string * name ;
798-
799- php_var_serialize_class_name (buf , struc );
800- php_var_serialize_collect_names (& names , HASH_OF (retval_ptr ));
801-
802- smart_str_append_unsigned (buf , zend_hash_num_elements (& names ));
803- smart_str_appendl (buf , ":{" , 2 );
804-
805- ZVAL_NULL (& nval );
806- propers = zend_get_properties_for (struc , ZEND_PROP_PURPOSE_SERIALIZE );
797+ HashTable * props = zend_get_properties_for (struc , ZEND_PROP_PURPOSE_SERIALIZE );
798+ zval * name_val ;
807799
808- ZEND_HASH_FOREACH_STR_KEY (& names , name ) {
809- zend_string * prot_name , * priv_name ;
800+ zend_hash_init (ht , zend_hash_num_elements (sleep_retval ), NULL , ZVAL_PTR_DTOR , 0 );
801+ ZEND_HASH_FOREACH_VAL (sleep_retval , name_val ) {
802+ zend_string * name , * tmp_name , * priv_name , * prot_name ;
810803
811- zval * val = zend_hash_find_ex (propers , name , 1 );
812- if (val != NULL ) {
813- if (Z_TYPE_P (val ) == IS_INDIRECT ) {
814- val = Z_INDIRECT_P (val );
815- if (Z_TYPE_P (val ) == IS_UNDEF ) {
816- goto undef_prop ;
817- }
818- }
804+ ZVAL_DEREF (name_val );
805+ if (Z_TYPE_P (name_val ) != IS_STRING ) {
806+ php_error_docref (NULL , E_NOTICE ,
807+ "__sleep should return an array only containing the names of instance-variables to serialize." );
808+ }
819809
820- php_var_serialize_string (buf , ZSTR_VAL (name ), ZSTR_LEN (name ));
821- php_var_serialize_intern (buf , val , var_hash );
810+ name = zval_get_tmp_string (name_val , & tmp_name );
811+ if (php_var_serialize_try_add_sleep_prop (ht , props , name , name ) == SUCCESS ) {
812+ zend_tmp_string_release (tmp_name );
822813 continue ;
823814 }
824815
825816 priv_name = zend_mangle_property_name (
826- ZSTR_VAL (ce -> name ), ZSTR_LEN (ce -> name ), ZSTR_VAL (name ), ZSTR_LEN (name ), 0 );
827- val = zend_hash_find (propers , priv_name );
828- if (val != NULL ) {
829- if (Z_TYPE_P (val ) == IS_INDIRECT ) {
830- val = Z_INDIRECT_P (val );
831- if (Z_ISUNDEF_P (val )) {
832- zend_string_free (priv_name );
833- goto undef_prop ;
834- }
835- }
836-
837- php_var_serialize_string (buf , ZSTR_VAL (priv_name ), ZSTR_LEN (priv_name ));
838- zend_string_free (priv_name );
839- php_var_serialize_intern (buf , val , var_hash );
817+ ZSTR_VAL (ce -> name ), ZSTR_LEN (ce -> name ),
818+ ZSTR_VAL (name ), ZSTR_LEN (name ), ce -> type & ZEND_INTERNAL_CLASS );
819+ if (php_var_serialize_try_add_sleep_prop (ht , props , priv_name , name ) == SUCCESS ) {
820+ zend_tmp_string_release (tmp_name );
821+ zend_string_release (priv_name );
840822 continue ;
841823 }
842- zend_string_free (priv_name );
824+ zend_string_release (priv_name );
843825
844826 prot_name = zend_mangle_property_name (
845- "*" , 1 , ZSTR_VAL (name ), ZSTR_LEN (name ), 0 );
846- val = zend_hash_find (propers , prot_name );
847- if (val != NULL ) {
848- if (Z_TYPE_P (val ) == IS_INDIRECT ) {
849- val = Z_INDIRECT_P (val );
850- if (Z_TYPE_P (val ) == IS_UNDEF ) {
851- zend_string_free (prot_name );
852- goto undef_prop ;
853- }
854- }
855-
856- php_var_serialize_string (buf , ZSTR_VAL (prot_name ), ZSTR_LEN (prot_name ));
857- zend_string_free (prot_name );
858- php_var_serialize_intern (buf , val , var_hash );
827+ "*" , 1 , ZSTR_VAL (name ), ZSTR_LEN (name ), ce -> type & ZEND_INTERNAL_CLASS );
828+ if (php_var_serialize_try_add_sleep_prop (ht , props , prot_name , name ) == SUCCESS ) {
829+ zend_tmp_string_release (tmp_name );
830+ zend_string_release (prot_name );
859831 continue ;
860832 }
861- zend_string_free (prot_name );
833+ zend_string_release (prot_name );
862834
863- undef_prop :
864- php_var_serialize_string (buf , ZSTR_VAL (name ), ZSTR_LEN (name ));
865- php_var_serialize_intern (buf , & nval , var_hash );
866835 php_error_docref (NULL , E_NOTICE ,
867- "\"%s\" returned as member variable from __sleep() but does not exist" , ZSTR_VAL (name ));
836+ "\"%s\" returned as member variable from __sleep() but does not exist" , ZSTR_VAL (name ));
837+ zend_hash_add (ht , name , & EG (uninitialized_zval ));
838+ zend_tmp_string_release (tmp_name );
868839 } ZEND_HASH_FOREACH_END ();
840+ zend_release_properties (props );
841+ }
842+ /* }}} */
843+
844+ static void php_var_serialize_nested_data (smart_str * buf , zval * struc , HashTable * ht , uint32_t count , zend_bool incomplete_class , php_serialize_data_t var_hash ) /* {{{ */
845+ {
846+ smart_str_append_unsigned (buf , count );
847+ smart_str_appendl (buf , ":{" , 2 );
848+ if (count > 0 ) {
849+ zend_string * key ;
850+ zval * data ;
851+ zend_ulong index ;
852+
853+ ZEND_HASH_FOREACH_KEY_VAL_IND (ht , index , key , data ) {
854+ if (incomplete_class && strcmp (ZSTR_VAL (key ), MAGIC_MEMBER ) == 0 ) {
855+ continue ;
856+ }
857+
858+ if (!key ) {
859+ php_var_serialize_long (buf , index );
860+ } else {
861+ php_var_serialize_string (buf , ZSTR_VAL (key ), ZSTR_LEN (key ));
862+ }
863+
864+ if (Z_ISREF_P (data ) && Z_REFCOUNT_P (data ) == 1 ) {
865+ data = Z_REFVAL_P (data );
866+ }
867+
868+ /* we should still add element even if it's not OK,
869+ * since we already wrote the length of the array before */
870+ if (Z_TYPE_P (data ) == IS_ARRAY ) {
871+ if (UNEXPECTED (Z_IS_RECURSIVE_P (data ))
872+ || UNEXPECTED (Z_TYPE_P (struc ) == IS_ARRAY && Z_ARR_P (data ) == Z_ARR_P (struc ))) {
873+ php_add_var_hash (var_hash , struc );
874+ smart_str_appendl (buf , "N;" , 2 );
875+ } else {
876+ if (Z_REFCOUNTED_P (data )) {
877+ Z_PROTECT_RECURSION_P (data );
878+ }
879+ php_var_serialize_intern (buf , data , var_hash );
880+ if (Z_REFCOUNTED_P (data )) {
881+ Z_UNPROTECT_RECURSION_P (data );
882+ }
883+ }
884+ } else {
885+ php_var_serialize_intern (buf , data , var_hash );
886+ }
887+ } ZEND_HASH_FOREACH_END ();
888+ }
869889 smart_str_appendc (buf , '}' );
890+ }
891+ /* }}} */
870892
871- zend_hash_destroy (& names );
872- zend_release_properties (propers );
893+ static void php_var_serialize_class (smart_str * buf , zval * struc , zval * retval_ptr , php_serialize_data_t var_hash ) /* {{{ */
894+ {
895+ HashTable props ;
896+ php_var_serialize_get_sleep_props (& props , struc , HASH_OF (retval_ptr ));
897+ php_var_serialize_class_name (buf , struc );
898+ php_var_serialize_nested_data (
899+ buf , struc , & props , zend_hash_num_elements (& props ), /* incomplete_class */ 0 , var_hash );
900+ zend_hash_destroy (& props );
873901}
874902/* }}} */
875903
@@ -933,6 +961,8 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
933961
934962 case IS_OBJECT : {
935963 zend_class_entry * ce = Z_OBJCE_P (struc );
964+ zend_bool incomplete_class ;
965+ uint32_t count ;
936966
937967 if (zend_hash_str_exists (& ce -> function_table , "__serialize" , sizeof ("__serialize" )- 1 )) {
938968 zval retval , obj ;
@@ -1023,75 +1053,24 @@ static void php_var_serialize_intern(smart_str *buf, zval *struc, php_serialize_
10231053 return ;
10241054 }
10251055
1026- /* fall-through */
1027- }
1028- case IS_ARRAY : {
1029- uint32_t i ;
1030- zend_bool incomplete_class = 0 ;
1031- if (Z_TYPE_P (struc ) == IS_ARRAY ) {
1032- smart_str_appendl (buf , "a:" , 2 );
1033- myht = Z_ARRVAL_P (struc );
1034- i = zend_array_count (myht );
1035- } else {
10361056 incomplete_class = php_var_serialize_class_name (buf , struc );
10371057 myht = zend_get_properties_for (struc , ZEND_PROP_PURPOSE_SERIALIZE );
10381058 /* count after serializing name, since php_var_serialize_class_name
10391059 * changes the count if the variable is incomplete class */
1040- i = zend_array_count (myht );
1041- if (i > 0 && incomplete_class ) {
1042- -- i ;
1060+ count = zend_array_count (myht );
1061+ if (count > 0 && incomplete_class ) {
1062+ -- count ;
10431063 }
1044- }
1045- smart_str_append_unsigned (buf , i );
1046- smart_str_appendl (buf , ":{" , 2 );
1047- if (i > 0 ) {
1048- zend_string * key ;
1049- zval * data ;
1050- zend_ulong index ;
1051-
1052- ZEND_HASH_FOREACH_KEY_VAL_IND (myht , index , key , data ) {
1053-
1054- if (incomplete_class && strcmp (ZSTR_VAL (key ), MAGIC_MEMBER ) == 0 ) {
1055- continue ;
1056- }
1057-
1058- if (!key ) {
1059- php_var_serialize_long (buf , index );
1060- } else {
1061- php_var_serialize_string (buf , ZSTR_VAL (key ), ZSTR_LEN (key ));
1062- }
1063-
1064- if (Z_ISREF_P (data ) && Z_REFCOUNT_P (data ) == 1 ) {
1065- data = Z_REFVAL_P (data );
1066- }
1067-
1068- /* we should still add element even if it's not OK,
1069- * since we already wrote the length of the array before */
1070- if (Z_TYPE_P (data ) == IS_ARRAY ) {
1071- if (UNEXPECTED (Z_IS_RECURSIVE_P (data ))
1072- || UNEXPECTED (Z_TYPE_P (struc ) == IS_ARRAY && Z_ARR_P (data ) == Z_ARR_P (struc ))) {
1073- php_add_var_hash (var_hash , struc );
1074- smart_str_appendl (buf , "N;" , 2 );
1075- } else {
1076- if (Z_REFCOUNTED_P (data )) {
1077- Z_PROTECT_RECURSION_P (data );
1078- }
1079- php_var_serialize_intern (buf , data , var_hash );
1080- if (Z_REFCOUNTED_P (data )) {
1081- Z_UNPROTECT_RECURSION_P (data );
1082- }
1083- }
1084- } else {
1085- php_var_serialize_intern (buf , data , var_hash );
1086- }
1087- } ZEND_HASH_FOREACH_END ();
1088- }
1089- smart_str_appendc (buf , '}' );
1090- if (Z_TYPE_P (struc ) == IS_OBJECT ) {
1064+ php_var_serialize_nested_data (buf , struc , myht , count , incomplete_class , var_hash );
10911065 zend_release_properties (myht );
1066+ return ;
10921067 }
1068+ case IS_ARRAY :
1069+ smart_str_appendl (buf , "a:" , 2 );
1070+ myht = Z_ARRVAL_P (struc );
1071+ php_var_serialize_nested_data (
1072+ buf , struc , myht , zend_array_count (myht ), /* incomplete_class */ 0 , var_hash );
10931073 return ;
1094- }
10951074 case IS_REFERENCE :
10961075 struc = Z_REFVAL_P (struc );
10971076 goto again ;
0 commit comments