1818
1919#include "php.h"
2020#include "ext/standard/php_var.h"
21-
21+ #include "zend_attributes.h"
22+ #include "ext/user_cache/php_user_cache.h" /* For user_cache safe direct path */
2223#include "zend_smart_str.h"
2324#include "zend_interfaces.h"
2425#include "zend_exceptions.h"
2930#include "spl_exceptions.h"
3031#include "spl_functions.h" /* For spl_set_private_debug_info_property() */
3132
32- #include "ext/user_cache/php_user_cache.h" /* For user_cache safe direct path */
33-
3433/* Defined later in the file */
3534PHPAPI zend_class_entry * spl_ce_ArrayIterator ;
3635PHPAPI zend_class_entry * spl_ce_RecursiveArrayIterator ;
@@ -63,6 +62,12 @@ static inline HashTable **spl_array_get_hash_table_ptr(spl_array_object* intern)
6362 if (intern -> ar_flags & SPL_ARRAY_IS_SELF ) {
6463 /* rebuild properties */
6564 zend_std_get_properties_ex (& intern -> std );
65+ if (GC_REFCOUNT (intern -> std .properties ) > 1 ) {
66+ if (EXPECTED (!(GC_FLAGS (intern -> std .properties ) & IS_ARRAY_IMMUTABLE ))) {
67+ GC_DELREF (intern -> std .properties );
68+ }
69+ intern -> std .properties = zend_array_dup (intern -> std .properties );
70+ }
6671 return & intern -> std .properties ;
6772 } else if (intern -> ar_flags & SPL_ARRAY_USE_OTHER ) {
6873 spl_array_object * other = Z_SPLARRAY_P (& intern -> array );
@@ -1406,8 +1411,6 @@ PHP_METHOD(ArrayObject, unserialize)
14061411
14071412} /* }}} */
14081413
1409- /* Builds the state array shared by __serialize() and the user-cache safe-direct
1410- * path. The members slot only exists in the __serialize() format. */
14111414static void spl_array_object_serialize_state (zval * object , zval * return_value , bool with_members )
14121415{
14131416 spl_array_object * intern = Z_SPLARRAY_P (object );
@@ -1449,8 +1452,6 @@ static void spl_array_object_serialize_state(zval *object, zval *return_value, b
14491452 zend_hash_next_index_insert (Z_ARRVAL_P (return_value ), & tmp );
14501453}
14511454
1452- /* Restores the state array built above. Throws and returns false on malformed
1453- * data; the caller decides how to propagate the failure. */
14541455static PHP_UCACHE_HOT bool spl_array_object_unserialize_state (zval * object , HashTable * data , bool with_members )
14551456{
14561457 spl_array_object * intern = Z_SPLARRAY_P (object );
@@ -1551,11 +1552,11 @@ PHP_METHOD(ArrayObject, __unserialize)
15511552}
15521553/* }}} */
15531554
1554- static bool spl_array_object_copy_user_cache_state (
1555+ static bool spl_array_object_copy_ucache_state (
15551556 void * ctx ,
15561557 zend_object * new_obj ,
15571558 zend_object * old_obj ,
1558- php_ucache_safe_direct_clone_value_func_t clone_value )
1559+ php_ucache_safe_direct_clone_val_func_t clone_value )
15591560{
15601561 spl_array_object * old_intern , * new_intern ;
15611562 zval new_zv , cloned_storage_zv ;
@@ -1579,57 +1580,66 @@ static bool spl_array_object_copy_user_cache_state(
15791580
15801581 result = true;
15811582
1582- goto bailout ;
1583+ goto cleanup ;
15831584 }
15841585
15851586 if (!clone_value (ctx , & cloned_storage_zv , & old_intern -> array ) ||
15861587 (Z_TYPE (cloned_storage_zv ) != IS_OBJECT && Z_TYPE (cloned_storage_zv ) != IS_ARRAY )
15871588 ) {
1588- goto bailout ;
1589+ goto cleanup ;
15891590 }
15901591
15911592 spl_array_set_array (& new_zv , new_intern , & cloned_storage_zv , old_intern -> ar_flags & SPL_ARRAY_CLONE_MASK , true);
15921593 result = !EG (exception );
15931594
1594- bailout :
1595- zval_ptr_dtor (& cloned_storage_zv );
1595+ cleanup :
1596+ if (Z_TYPE (cloned_storage_zv ) != IS_UNDEF ) {
1597+ zval_ptr_dtor (& cloned_storage_zv );
1598+ }
15961599
15971600 return result ;
15981601}
15991602
1600- static bool spl_array_object_user_cache_state_has_unstorable (
1601- void * ctx ,
1602- const zval * object ,
1603- php_ucache_safe_direct_value_has_unstorable_func_t value_has_unstorable )
1603+ static bool spl_array_object_serialize_ucache_state (zval * state , const zval * object )
16041604{
1605- spl_array_object * intern = Z_SPLARRAY_P (object );
1605+ zval * storage ;
1606+
1607+ ZVAL_UNDEF (state );
1608+
1609+ spl_array_object_serialize_state ((zval * ) object , state , /* with_members */ false);
1610+
1611+ if (EG (exception ) || Z_TYPE_P (state ) != IS_ARRAY ) {
1612+ if (Z_TYPE_P (state ) != IS_UNDEF ) {
1613+ zval_ptr_dtor (state );
1614+ }
1615+
1616+ ZVAL_UNDEF (state );
16061617
1607- if (intern -> ar_flags & SPL_ARRAY_IS_SELF ) {
16081618 return false;
16091619 }
16101620
1611- return value_has_unstorable (ctx , & intern -> array );
1612- }
1613-
1614- static bool spl_array_object_serialize_user_cache_state (zval * state , const zval * object )
1615- {
1616- spl_array_object_serialize_state ((zval * ) object , state , /* with_members */ false);
1621+ storage = zend_hash_index_find (Z_ARRVAL_P (state ), 1 );
1622+ if (storage != NULL && Z_TYPE_P (storage ) == IS_ARRAY ) {
1623+ SEPARATE_ARRAY (storage );
1624+ }
16171625
16181626 return true;
16191627}
16201628
1621- static PHP_UCACHE_HOT bool spl_array_object_unserialize_user_cache_state (zval * object , zval * state )
1629+ static PHP_UCACHE_HOT bool spl_array_object_unserialize_ucache_state (zval * object , zval * state )
16221630{
1631+ if (Z_TYPE_P (state ) != IS_ARRAY ) {
1632+ return false;
1633+ }
1634+
16231635 return spl_array_object_unserialize_state (object , Z_ARRVAL_P (state ), /* with_members */ false)
1624- && !EG (exception )
1625- ;
1636+ && !EG (exception );
16261637}
16271638
1628- static const php_ucache_safe_direct_handlers_t spl_array_user_cache_handlers = {
1629- .copy = spl_array_object_copy_user_cache_state ,
1630- .state_has_unstorable = spl_array_object_user_cache_state_has_unstorable ,
1631- .state_serialize = spl_array_object_serialize_user_cache_state ,
1632- .state_unserialize = spl_array_object_unserialize_user_cache_state ,
1639+ static const php_ucache_safe_direct_handlers spl_array_ucache_handlers = {
1640+ .copy = spl_array_object_copy_ucache_state ,
1641+ .state_serialize = spl_array_object_serialize_ucache_state ,
1642+ .state_unserialize = spl_array_object_unserialize_ucache_state ,
16331643};
16341644
16351645/* {{{ */
@@ -2011,8 +2021,8 @@ PHP_MINIT_FUNCTION(spl_array)
20112021 spl_ce_RecursiveArrayIterator -> create_object = spl_array_object_new ;
20122022 spl_ce_RecursiveArrayIterator -> get_iterator = spl_array_get_iterator ;
20132023
2014- php_ucache_safe_direct_register_class (spl_ce_ArrayObject , & spl_array_user_cache_handlers );
2015- php_ucache_safe_direct_register_class (spl_ce_ArrayIterator , & spl_array_user_cache_handlers );
2024+ php_ucache_safe_direct_register_class (spl_ce_ArrayObject , & spl_array_ucache_handlers );
2025+ php_ucache_safe_direct_register_class (spl_ce_ArrayIterator , & spl_array_ucache_handlers );
20162026
20172027 return SUCCESS ;
20182028}
0 commit comments