Skip to content

Commit 5d907df

Browse files
committed
Merge branch 'PHP-8.0' into PHP-8.1
2 parents e80ec3f + cd1c6f0 commit 5d907df

File tree

2 files changed

+61
-0
lines changed

2 files changed

+61
-0
lines changed

ext/spl/spl_fixedarray.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@ typedef struct _spl_fixedarray {
4444
zend_long size;
4545
/* It is possible to resize this, so this can't be combined with the object */
4646
zval *elements;
47+
/* True if this was modified after the last call to get_properties or the hash table wasn't rebuilt. */
48+
bool should_rebuild_properties;
4749
} spl_fixedarray;
4850

4951
typedef struct _spl_fixedarray_methods {
@@ -110,6 +112,7 @@ static void spl_fixedarray_init(spl_fixedarray *array, zend_long size)
110112
array->size = 0; /* reset size in case ecalloc() fails */
111113
array->elements = safe_emalloc(size, sizeof(zval), 0);
112114
array->size = size;
115+
array->should_rebuild_properties = true;
113116
spl_fixedarray_init_elems(array, 0, size);
114117
} else {
115118
spl_fixedarray_default_ctor(array);
@@ -173,6 +176,7 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size)
173176
/* nothing to do */
174177
return;
175178
}
179+
array->should_rebuild_properties = true;
176180

177181
/* first initialization */
178182
if (array->size == 0) {
@@ -212,6 +216,22 @@ static HashTable* spl_fixedarray_object_get_properties(zend_object *obj)
212216
HashTable *ht = zend_std_get_properties(obj);
213217

214218
if (!spl_fixedarray_empty(&intern->array)) {
219+
/*
220+
* Usually, the reference count of the hash table is 1,
221+
* except during cyclic reference cycles.
222+
*
223+
* Maintain the DEBUG invariant that a hash table isn't modified during iteration,
224+
* and avoid unnecessary work rebuilding a hash table for unmodified properties.
225+
*
226+
* See https://github.com/php/php-src/issues/8079 and ext/spl/tests/fixedarray_022.phpt
227+
* Also see https://github.com/php/php-src/issues/8044 for alternate considered approaches.
228+
*/
229+
if (!intern->array.should_rebuild_properties) {
230+
/* Return the same hash table so that recursion cycle detection works in internal functions. */
231+
return ht;
232+
}
233+
intern->array.should_rebuild_properties = false;
234+
215235
zend_long j = zend_hash_num_elements(ht);
216236

217237
if (GC_REFCOUNT(ht) > 1) {
@@ -398,6 +418,9 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
398418
}
399419
return &EG(uninitialized_zval);
400420
}
421+
if (type != BP_VAR_IS && type != BP_VAR_R) {
422+
intern->array.should_rebuild_properties = true;
423+
}
401424

402425
return spl_fixedarray_object_read_dimension_helper(intern, offset);
403426
}
@@ -422,6 +445,7 @@ static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *
422445
zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
423446
return;
424447
} else {
448+
intern->array.should_rebuild_properties = true;
425449
/* Fix #81429 */
426450
zval *ptr = &(intern->array.elements[index]);
427451
zval tmp;
@@ -464,6 +488,7 @@ static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *
464488
zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
465489
return;
466490
} else {
491+
intern->array.should_rebuild_properties = true;
467492
zval_ptr_dtor(&(intern->array.elements[index]));
468493
ZVAL_NULL(&intern->array.elements[index]);
469494
}

ext/spl/tests/fixedarray_023.phpt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
--TEST--
2+
SPL: FixedArray: Infinite loop in var_export bugfix
3+
--FILE--
4+
<?php
5+
call_user_func(function () {
6+
$x = new SplFixedArray(4);
7+
$x[0] = NAN; // Test NAN just in case this check is incorrectly refactored to use zend_is_identical
8+
$x[1] = 0.0;
9+
$x[2] = $x;
10+
$x[3] = $x;
11+
var_export($x);
12+
echo "\n";
13+
$x[1] = -0.0;
14+
debug_zval_dump($x);
15+
});
16+
?>
17+
--EXPECTF--
18+
Warning: var_export does not handle circular references in %s on line 8
19+
20+
Warning: var_export does not handle circular references in %s on line 8
21+
SplFixedArray::__set_state(array(
22+
0 => NAN,
23+
1 => 0.0,
24+
2 => NULL,
25+
3 => NULL,
26+
))
27+
object(SplFixedArray)#2 (4) refcount(6){
28+
[0]=>
29+
float(NAN)
30+
[1]=>
31+
float(-0)
32+
[2]=>
33+
*RECURSION*
34+
[3]=>
35+
*RECURSION*
36+
}

0 commit comments

Comments
 (0)