Skip to content

Commit b50315e

Browse files
committed
Merge branch 'PHP-8.1'
Conflicts: ext/spl/tests/fixedarray_023.phpt ext/spl/spl_fixedarray.c (fix compile error)
2 parents 11cedf4 + 5d907df commit b50315e

File tree

3 files changed

+68
-7
lines changed

3 files changed

+68
-7
lines changed

ext/spl/spl_fixedarray.c

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,8 @@ typedef struct _spl_fixedarray {
4848
zend_long size;
4949
/* It is possible to resize this, so this can't be combined with the object */
5050
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;
5153
} spl_fixedarray;
5254

5355
typedef struct _spl_fixedarray_object {
@@ -106,6 +108,7 @@ static void spl_fixedarray_init(spl_fixedarray *array, zend_long size)
106108
array->size = 0; /* reset size in case ecalloc() fails */
107109
array->elements = safe_emalloc(size, sizeof(zval), 0);
108110
array->size = size;
111+
array->should_rebuild_properties = true;
109112
spl_fixedarray_init_elems(array, 0, size);
110113
} else {
111114
spl_fixedarray_default_ctor(array);
@@ -169,6 +172,7 @@ static void spl_fixedarray_resize(spl_fixedarray *array, zend_long size)
169172
/* nothing to do */
170173
return;
171174
}
175+
array->should_rebuild_properties = true;
172176

173177
/* first initialization */
174178
if (array->size == 0) {
@@ -208,6 +212,22 @@ static HashTable* spl_fixedarray_object_get_properties(zend_object *obj)
208212
HashTable *ht = zend_std_get_properties(obj);
209213

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

213233
if (GC_REFCOUNT(ht) > 1) {
@@ -370,6 +390,9 @@ static zval *spl_fixedarray_object_read_dimension(zend_object *object, zval *off
370390
}
371391

372392
spl_fixedarray_object *intern = spl_fixed_array_from_obj(object);
393+
if (type != BP_VAR_IS && type != BP_VAR_R) {
394+
intern->array.should_rebuild_properties = true;
395+
}
373396
return spl_fixedarray_object_read_dimension_helper(intern, offset);
374397
}
375398

@@ -393,6 +416,7 @@ static void spl_fixedarray_object_write_dimension_helper(spl_fixedarray_object *
393416
zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
394417
return;
395418
} else {
419+
intern->array.should_rebuild_properties = true;
396420
/* Fix #81429 */
397421
zval *ptr = &(intern->array.elements[index]);
398422
zval tmp;
@@ -433,6 +457,7 @@ static void spl_fixedarray_object_unset_dimension_helper(spl_fixedarray_object *
433457
zend_throw_exception(spl_ce_RuntimeException, "Index invalid or out of range", 0);
434458
return;
435459
} else {
460+
intern->array.should_rebuild_properties = true;
436461
zval_ptr_dtor(&(intern->array.elements[index]));
437462
ZVAL_NULL(&intern->array.elements[index]);
438463
}

ext/spl/tests/fixedarray_023.phpt

Lines changed: 32 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,36 @@
11
--TEST--
2-
SPL: FixedArray: Bug GH-8041 (php 8.2.0-dev crashes with assertion for cloning/get_object_vars on non-empty SplFixedArray)
2+
SPL: FixedArray: Infinite loop in var_export bugfix
33
--FILE--
44
<?php
5-
$x = new SplFixedArray(1);
6-
$z = (array)$x;
7-
$y = clone $x;
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+
});
816
?>
9-
DONE
10-
--EXPECT--
11-
DONE
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+
}

ext/spl/tests/fixedarray_024.phpt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--TEST--
2+
SPL: FixedArray: Bug GH-8041 (php 8.2.0-dev crashes with assertion for cloning/get_object_vars on non-empty SplFixedArray)
3+
--FILE--
4+
<?php
5+
$x = new SplFixedArray(1);
6+
$z = (array)$x;
7+
$y = clone $x;
8+
?>
9+
DONE
10+
--EXPECT--
11+
DONE

0 commit comments

Comments
 (0)