@@ -44,8 +44,6 @@ typedef struct _spl_array_object {
4444 uint32_t ht_iter ;
4545 int ar_flags ;
4646 unsigned char nApplyCount ;
47- bool is_child ;
48- Bucket * bucket ;
4947 zend_function * fptr_offset_get ;
5048 zend_function * fptr_offset_set ;
5149 zend_function * fptr_offset_has ;
@@ -166,8 +164,6 @@ static zend_object *spl_array_object_new_ex(zend_class_entry *class_type, zend_o
166164 object_properties_init (& intern -> std , class_type );
167165
168166 intern -> ar_flags = 0 ;
169- intern -> is_child = false;
170- intern -> bucket = NULL ;
171167 intern -> ce_get_iterator = spl_ce_ArrayIterator ;
172168 if (orig ) {
173169 spl_array_object * other = spl_array_from_obj (orig );
@@ -466,20 +462,12 @@ static zval *spl_array_read_dimension(zend_object *object, zval *offset, int typ
466462} /* }}} */
467463
468464/*
469- * The assertion(HT_ASSERT_RC1(ht)) failed because the refcount was increased manually when intern->is_child is true.
470- * We have to set the refcount to 1 to make assertion success and restore the refcount to the original value after
471- * modifying the array when intern->is_child is true.
465+ * Before modifying the internal array, we must ensure exclusive ownership
466+ * to satisfy HT_ASSERT_RC1 in Zend hash operations.
467+ *
468+ * SEPARATE_ARRAY implements CoW: if the array is shared (RC > 1),
469+ * it creates a duplicate via zend_array_dup() and updates intern->array.
472470 */
473- static uint32_t spl_array_set_refcount (bool is_child , HashTable * ht , uint32_t refcount ) /* {{{ */
474- {
475- uint32_t old_refcount = 0 ;
476- if (is_child ) {
477- old_refcount = GC_REFCOUNT (ht );
478- GC_SET_REFCOUNT (ht , refcount );
479- }
480-
481- return old_refcount ;
482- } /* }}} */
483471
484472static void spl_array_write_dimension_ex (int check_inherited , zend_object * object , zval * offset , zval * value ) /* {{{ */
485473{
@@ -505,18 +493,15 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
505493
506494 Z_TRY_ADDREF_P (value );
507495
508- uint32_t refcount = 0 ;
509496 if (!offset || Z_TYPE_P (offset ) == IS_NULL ) {
497+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
498+ SEPARATE_ARRAY (& intern -> array );
499+ }
510500 ht = spl_array_get_hash_table (intern );
511501 if (UNEXPECTED (ht == intern -> sentinel_array )) {
512502 return ;
513503 }
514- refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
515504 zend_hash_next_index_insert (ht , value );
516-
517- if (refcount ) {
518- spl_array_set_refcount (intern -> is_child , ht , refcount );
519- }
520505 return ;
521506 }
522507
@@ -526,22 +511,20 @@ static void spl_array_write_dimension_ex(int check_inherited, zend_object *objec
526511 return ;
527512 }
528513
514+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
515+ SEPARATE_ARRAY (& intern -> array );
516+ }
529517 ht = spl_array_get_hash_table (intern );
530518 if (UNEXPECTED (ht == intern -> sentinel_array )) {
531519 spl_hash_key_release (& key );
532520 return ;
533521 }
534- refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
535522 if (key .key ) {
536523 zend_hash_update_ind (ht , key .key , value );
537524 spl_hash_key_release (& key );
538525 } else {
539526 zend_hash_index_update (ht , key .h , value );
540527 }
541-
542- if (refcount ) {
543- spl_array_set_refcount (intern -> is_child , ht , refcount );
544- }
545528} /* }}} */
546529
547530static void spl_array_write_dimension (zend_object * object , zval * offset , zval * value ) /* {{{ */
@@ -570,8 +553,10 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
570553 return ;
571554 }
572555
556+ if (Z_TYPE (intern -> array ) == IS_ARRAY ) {
557+ SEPARATE_ARRAY (& intern -> array );
558+ }
573559 ht = spl_array_get_hash_table (intern );
574- uint32_t refcount = spl_array_set_refcount (intern -> is_child , ht , 1 );
575560
576561 if (key .key ) {
577562 zval * data = zend_hash_find (ht , key .key );
@@ -597,10 +582,6 @@ static void spl_array_unset_dimension_ex(int check_inherited, zend_object *objec
597582 } else {
598583 zend_hash_index_del (ht , key .h );
599584 }
600-
601- if (refcount ) {
602- spl_array_set_refcount (intern -> is_child , ht , refcount );
603- }
604585} /* }}} */
605586
606587static void spl_array_unset_dimension (zend_object * object , zval * offset ) /* {{{ */
@@ -970,17 +951,7 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar
970951 if (Z_REFCOUNT_P (array ) == 1 ) {
971952 ZVAL_COPY (& intern -> array , array );
972953 } else {
973- //??? TODO: try to avoid array duplication
974954 ZVAL_ARR (& intern -> array , zend_array_dup (Z_ARR_P (array )));
975-
976- if (intern -> is_child ) {
977- Z_TRY_DELREF (intern -> bucket -> val );
978- /*
979- * replace bucket->val with copied array, so the changes between
980- * parent and child object can affect each other.
981- */
982- ZVAL_COPY (& intern -> bucket -> val , & intern -> array );
983- }
984955 }
985956 } else {
986957 php_error_docref (NULL , E_DEPRECATED ,
@@ -1850,15 +1821,6 @@ PHP_METHOD(RecursiveArrayIterator, hasChildren)
18501821static void spl_instantiate_child_arg (zend_class_entry * pce , zval * retval , zval * arg1 , zval * arg2 ) /* {{{ */
18511822{
18521823 object_init_ex (retval , pce );
1853- spl_array_object * new_intern = Z_SPLARRAY_P (retval );
1854- /*
1855- * set new_intern->is_child is true to indicate that the object was created by
1856- * RecursiveArrayIterator::getChildren() method.
1857- */
1858- new_intern -> is_child = true;
1859-
1860- /* find the bucket of parent object. */
1861- new_intern -> bucket = (Bucket * )((char * )(arg1 ) - XtOffsetOf (Bucket , val ));;
18621824 zend_call_known_instance_method_with_2_params (pce -> constructor , Z_OBJ_P (retval ), NULL , arg1 , arg2 );
18631825}
18641826/* }}} */
0 commit comments