diff --git a/NEWS b/NEWS index 4a8352c8a80..68df6ab75ae 100644 --- a/NEWS +++ b/NEWS @@ -11,6 +11,10 @@ PHP NEWS . Fixed GH-12077 (PHP 8.3.0RC1 borked socket-close-on-exec.phpt). (Jakub Zelenka) +- SPL: + . Fixed bug GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18). + (nielsdos) + 31 Aug 2023, PHP 8.3.0RC1 - Core: diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index 2e67b3cfe8c..79802454e3f 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -1060,13 +1060,12 @@ static void spl_array_set_array(zval *object, spl_array_object *intern, zval *ar ZVAL_ARR(&intern->array, zend_array_dup(Z_ARR_P(array))); if (intern->is_child) { - Z_TRY_DELREF_P(&intern->bucket->val); + Z_TRY_DELREF(intern->bucket->val); /* * replace bucket->val with copied array, so the changes between * parent and child object can affect each other. */ - intern->bucket->val = intern->array; - Z_TRY_ADDREF_P(&intern->array); + ZVAL_COPY(&intern->bucket->val, &intern->array); } } } else { diff --git a/ext/spl/tests/gh11972.phpt b/ext/spl/tests/gh11972.phpt new file mode 100644 index 00000000000..d88d7c5ecae --- /dev/null +++ b/ext/spl/tests/gh11972.phpt @@ -0,0 +1,196 @@ +--TEST-- +GH-11972 (RecursiveCallbackFilterIterator regression in 8.1.18) +--EXTENSIONS-- +spl +--FILE-- +setMaxDepth(20); + foreach ($recursive_iterator as $value) { + // Avoid recursion by marking where we've been. + $value['#override_mode_breadcrumb'] = true; + } + return \iterator_to_array($recursive_iterator); + } + + public function isCyclic($current, string $key, \RecursiveArrayIterator $iterator): bool { + var_dump($current); + if (!is_array($current)) { + return false; + } + // Avoid infinite loops by checking if we've been here before. + // e.g. View > query > view > query ... + if (isset($current['#override_mode_breadcrumb'])) { + return false; + } + return true; + } +} + +$test_array['e']['p'][] = ['a', 'a']; +$test_array['e']['p'][] = ['b', 'b']; +$test_array['e']['p'][] = ['c', 'c']; +$serialized = serialize($test_array); +$unserialized = unserialize($serialized); + +$test_class = new RecursiveFilterTest(); +$test_class->traverse($unserialized); + +echo "Done\n"; + +?> +--EXPECT-- +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +array(1) { + ["p"]=> + array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } + } +} +array(3) { + [0]=> + array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" + } + [1]=> + array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" + } + [2]=> + array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" + } +} +array(2) { + [0]=> + string(1) "a" + [1]=> + string(1) "a" +} +string(1) "a" +string(1) "a" +array(2) { + [0]=> + string(1) "b" + [1]=> + string(1) "b" +} +string(1) "b" +string(1) "b" +array(2) { + [0]=> + string(1) "c" + [1]=> + string(1) "c" +} +string(1) "c" +string(1) "c" +Done