@@ -48,8 +48,6 @@ typedef struct _spl_fixedarray {
48
48
zend_long size ;
49
49
/* It is possible to resize this, so this can't be combined with the object */
50
50
zval * elements ;
51
- /* True if this was modified after the last call to get_properties or the hash table wasn't rebuilt. */
52
- bool should_rebuild_properties ;
53
51
} spl_fixedarray ;
54
52
55
53
typedef struct _spl_fixedarray_object {
@@ -107,7 +105,6 @@ static void spl_fixedarray_init_non_empty_struct(spl_fixedarray *array, zend_lon
107
105
array -> size = 0 ; /* reset size in case ecalloc() fails */
108
106
array -> elements = size ? safe_emalloc (size , sizeof (zval ), 0 ) : NULL ;
109
107
array -> size = size ;
110
- array -> should_rebuild_properties = true;
111
108
}
112
109
113
110
static void spl_fixedarray_init (spl_fixedarray * array , zend_long size )
@@ -177,7 +174,6 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size)
177
174
/* nothing to do */
178
175
return ;
179
176
}
180
- array -> should_rebuild_properties = true;
181
177
182
178
/* first initialization */
183
179
if (array -> size == 0 ) {
@@ -211,47 +207,41 @@ static HashTable* spl_fixedarray_object_get_gc(zend_object *obj, zval **table, i
211
207
return ht ;
212
208
}
213
209
214
- static HashTable * spl_fixedarray_object_get_properties (zend_object * obj )
210
+ static HashTable * spl_fixedarray_object_get_properties_for (zend_object * obj , zend_prop_purpose purpose )
215
211
{
216
- spl_fixedarray_object * intern = spl_fixed_array_from_obj (obj );
217
- HashTable * ht = zend_std_get_properties (obj );
218
-
219
- if (!spl_fixedarray_empty (& intern -> array )) {
220
- /*
221
- * Usually, the reference count of the hash table is 1,
222
- * except during cyclic reference cycles.
223
- *
224
- * Maintain the DEBUG invariant that a hash table isn't modified during iteration,
225
- * and avoid unnecessary work rebuilding a hash table for unmodified properties.
226
- *
227
- * See https://github.com/php/php-src/issues/8079 and ext/spl/tests/fixedarray_022.phpt
228
- * Also see https://github.com/php/php-src/issues/8044 for alternate considered approaches.
229
- */
230
- if (!intern -> array .should_rebuild_properties ) {
231
- /* Return the same hash table so that recursion cycle detection works in internal functions. */
232
- return ht ;
233
- }
234
- intern -> array .should_rebuild_properties = false;
212
+ /* This has __serialize, so the purpose is not ZEND_PROP_PURPOSE_SERIALIZE, which would expect a non-null return value */
213
+ ZEND_ASSERT (purpose != ZEND_PROP_PURPOSE_SERIALIZE );
235
214
236
- zend_long j = zend_hash_num_elements (ht );
215
+ const spl_fixedarray_object * intern = spl_fixed_array_from_obj (obj );
216
+ /*
217
+ * SplFixedArray can be subclassed or have dynamic properties (With or without AllowDynamicProperties in subclasses).
218
+ * Instances of subclasses with declared properties may have properties but not yet have a property table.
219
+ */
220
+ HashTable * source_properties = obj -> properties ? obj -> properties : (obj -> ce -> default_properties_count ? zend_std_get_properties (obj ) : NULL );
237
221
238
- if (GC_REFCOUNT (ht ) > 1 ) {
239
- intern -> std .properties = zend_array_dup (ht );
240
- GC_TRY_DELREF (ht );
241
- }
242
- for (zend_long i = 0 ; i < intern -> array .size ; i ++ ) {
243
- zend_hash_index_update (ht , i , & intern -> array .elements [i ]);
244
- Z_TRY_ADDREF (intern -> array .elements [i ]);
245
- }
246
- if (j > intern -> array .size ) {
247
- for (zend_long i = intern -> array .size ; i < j ; ++ i ) {
248
- zend_hash_index_del (ht , i );
222
+ const zend_long size = intern -> array .size ;
223
+ if (size == 0 && (!source_properties || !zend_hash_num_elements (source_properties ))) {
224
+ return NULL ;
225
+ }
226
+ zval * const elements = intern -> array .elements ;
227
+ HashTable * ht = zend_new_array (size );
228
+
229
+ for (zend_long i = 0 ; i < size ; i ++ ) {
230
+ Z_TRY_ADDREF_P (& elements [i ]);
231
+ zend_hash_next_index_insert (ht , & elements [i ]);
232
+ }
233
+ if (source_properties && zend_hash_num_elements (source_properties ) > 0 ) {
234
+ zend_long nkey ;
235
+ zend_string * skey ;
236
+ zval * value ;
237
+ ZEND_HASH_MAP_FOREACH_KEY_VAL_IND (source_properties , nkey , skey , value ) {
238
+ Z_TRY_ADDREF_P (value );
239
+ if (skey ) {
240
+ zend_hash_add_new (ht , skey , value );
241
+ } else {
242
+ zend_hash_index_update (ht , nkey , value );
249
243
}
250
- }
251
- if (HT_IS_PACKED (ht )) {
252
- /* Engine doesn't expet packed array */
253
- zend_hash_packed_to_hash (ht );
254
- }
244
+ } ZEND_HASH_FOREACH_END ();
255
245
}
256
246
257
247
return ht ;
@@ -394,9 +384,6 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
394
384
}
395
385
396
386
spl_fixedarray_object * intern = spl_fixed_array_from_obj (object );
397
- if (type != BP_VAR_IS && type != BP_VAR_R ) {
398
- intern -> array .should_rebuild_properties = true;
399
- }
400
387
return spl_fixedarray_object_read_dimension_helper (intern , offset );
401
388
}
402
389
@@ -420,7 +407,6 @@ static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *
420
407
zend_throw_exception (spl_ce_RuntimeException , "Index invalid or out of range" , 0 );
421
408
return ;
422
409
} else {
423
- intern -> array .should_rebuild_properties = true;
424
410
/* Fix #81429 */
425
411
zval * ptr = & (intern -> array .elements [index ]);
426
412
zval tmp ;
@@ -461,7 +447,6 @@ static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *
461
447
zend_throw_exception (spl_ce_RuntimeException , "Index invalid or out of range" , 0 );
462
448
return ;
463
449
} else {
464
- intern -> array .should_rebuild_properties = true;
465
450
zval_ptr_dtor (& (intern -> array .elements [index ]));
466
451
ZVAL_NULL (& intern -> array .elements [index ]);
467
452
}
@@ -973,7 +958,7 @@ PHP_MINIT_FUNCTION(spl_fixedarray)
973
958
spl_handler_SplFixedArray .unset_dimension = spl_fixedarray_object_unset_dimension ;
974
959
spl_handler_SplFixedArray .has_dimension = spl_fixedarray_object_has_dimension ;
975
960
spl_handler_SplFixedArray .count_elements = spl_fixedarray_object_count_elements ;
976
- spl_handler_SplFixedArray .get_properties = spl_fixedarray_object_get_properties ;
961
+ spl_handler_SplFixedArray .get_properties_for = spl_fixedarray_object_get_properties_for ;
977
962
spl_handler_SplFixedArray .get_gc = spl_fixedarray_object_get_gc ;
978
963
spl_handler_SplFixedArray .free_obj = spl_fixedarray_object_free_storage ;
979
964
0 commit comments