From 92b458a5c934f2414178920fea2e8cfdcdb721c1 Mon Sep 17 00:00:00 2001 From: Gina Peter Banyard Date: Sat, 1 Jun 2024 03:47:55 +0100 Subject: [PATCH] Indirect support for fetching address --- ...rrayObject_container_offset_behaviour.phpt | 1 - Zend/zend_execute.c | 12 ++++- ext/spl/spl_array.c | 23 +++------- .../indirect_assign_reference_to_offset.phpt | 44 +++++++++++-------- ext/spl/tests/iterator_035.phpt | 17 ++++--- 5 files changed, 53 insertions(+), 44 deletions(-) diff --git a/Zend/tests/offsets/ArrayObject_container_offset_behaviour.phpt b/Zend/tests/offsets/ArrayObject_container_offset_behaviour.phpt index e352db42f8b97..1e0053d81297d 100644 --- a/Zend/tests/offsets/ArrayObject_container_offset_behaviour.phpt +++ b/Zend/tests/offsets/ArrayObject_container_offset_behaviour.phpt @@ -333,7 +333,6 @@ foreach ($offsets as $offset) { !preg_match($EXPECTED_OUTPUT_VALID_OFFSETS_REGEX, $varOutput) && !preg_match($EXPECTED_OUTPUT_INVALID_OFFSETS_REGEX, $varOutput) && !preg_match($EXPECTED_OUTPUT_FLOAT_OFFSETS_REGEX, $varOutput) - && $varOutput !== EXPECTED_OUTPUT_NULL_OFFSET && $varOutput !== EXPECTED_OUTPUT_RESOURCE_STDERR_OFFSETS ) { file_put_contents(__DIR__ . DIRECTORY_SEPARATOR . "debug_ArrayObject_container_{$failuresNb}.txt", $varOutput); diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 570fef7f955d1..fef5149564fe2 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2765,12 +2765,22 @@ static zend_never_inline void zend_fetch_object_dimension_address(zval *result, ZVAL_UNDEF(result); goto clean_up; } - if (!Z_ISREF_P(retval) && Z_TYPE_P(retval) != IS_OBJECT) { + if ( + !Z_ISREF_P(retval) + && Z_TYPE_P(retval) != IS_OBJECT + /* Indirect support is needed for supporting $ArrayObject[$i] = &$var; constructs */ + && Z_TYPE_P(retval) != IS_INDIRECT + ) { zend_class_entry *ce = obj->ce; zend_throw_error(NULL, "%s::%s() must return a reference type", ZSTR_VAL(ce->name), offset ? "offsetFetch" : "fetchAppend"); ZVAL_UNDEF(result); goto clean_up; + } else if (UNEXPECTED(Z_REFCOUNT_P(retval) == 1)) { + ZVAL_UNREF(retval); + } + if (result != retval) { + ZVAL_INDIRECT(result, retval); } } else { zend_use_object_as_array(obj); diff --git a/ext/spl/spl_array.c b/ext/spl/spl_array.c index a3449a99afd38..41e3fdaa651dd 100644 --- a/ext/spl/spl_array.c +++ b/ext/spl/spl_array.c @@ -397,19 +397,13 @@ static zval *spl_array_read_dimension_ex(zend_object *object, zval *offset, int //} if (type == BP_VAR_W) { - if (Z_TYPE_P(ret) == IS_OBJECT) { - ZVAL_COPY(rv, ret); - } else { - ZVAL_NEW_REF(ret, ret); - zend_reference *ref = Z_REF_P(ret); - GC_ADDREF(ref); - ZVAL_REF(rv, ref); - } + ZVAL_NEW_REF(ret, ret); + return ret; } else { ZVAL_COPY_DEREF(rv, ret); + return rv; } - return rv; } /* }}} */ static zval *spl_array_read_dimension(zend_object *object, zval *offset, zval *rv) /* {{{ */ @@ -511,20 +505,13 @@ static zval* spl_array_fetch_append(zend_object *object, zval *rv) ZVAL_NULL(&dummy); zval *ret = zend_hash_next_index_insert(ht, &dummy); - if (Z_TYPE_P(ret) == IS_OBJECT) { - ZVAL_COPY(rv, ret); - } else { - ZVAL_NEW_REF(ret, ret); - zend_reference *ref = Z_REF_P(ret); - GC_ADDREF(ref); - ZVAL_REF(rv, ref); - } + ZVAL_NEW_REF(ret, ret); if (refcount) { spl_array_set_refcount(intern->is_child, ht, refcount); } - return rv; + return ret; } static void spl_array_unset_dimension(zend_object *object, zval *offset) /* {{{ */ diff --git a/ext/spl/tests/ArrayObject/indirect_assign_reference_to_offset.phpt b/ext/spl/tests/ArrayObject/indirect_assign_reference_to_offset.phpt index 51858bc33ced4..f3b932a866523 100644 --- a/ext/spl/tests/ArrayObject/indirect_assign_reference_to_offset.phpt +++ b/ext/spl/tests/ArrayObject/indirect_assign_reference_to_offset.phpt @@ -1,45 +1,51 @@ --TEST-- -Bug #73686 (Adding settype()ed values to ArrayObject results in references) +Setting indirections must work for ArrayObject --FILE-- $var) { - settype($var, 'string'); - $ao[$i] = $var; + $a[$i] = &$var; } -var_dump($ao); +$a[] = &$var; +var_dump($a); +echo "Using ArrayObject\n"; $ao = new ArrayObject; - foreach ([1, 2, 3] as $i => $var) { $ao[$i] = &$var; } +$ao[] = &$var; var_dump($ao); ?> ---EXPECTF-- -object(ArrayObject)#%d (1) { - ["storage":"ArrayObject":private]=> - array(3) { - [0]=> - string(1) "1" - [1]=> - string(1) "2" - [2]=> - string(1) "3" - } +--EXPECT-- +Using array +array(4) { + [0]=> + &int(3) + [1]=> + &int(3) + [2]=> + &int(3) + [3]=> + &int(3) } -object(ArrayObject)#%d (1) { +Using ArrayObject +object(ArrayObject)#1 (1) { ["storage":"ArrayObject":private]=> - array(3) { + array(4) { [0]=> &int(3) [1]=> &int(3) [2]=> &int(3) + [3]=> + &int(3) } } diff --git a/ext/spl/tests/iterator_035.phpt b/ext/spl/tests/iterator_035.phpt index edf9811d93bd1..9f82a1b6b7046 100644 --- a/ext/spl/tests/iterator_035.phpt +++ b/ext/spl/tests/iterator_035.phpt @@ -9,10 +9,17 @@ $a = new ArrayIterator(); $a[] = $tmp; $a[] = &$tmp; +var_dump($a); echo "Done\n"; ?> ---EXPECTF-- -Fatal error: Uncaught Error: Cannot assign by reference to an array dimension of an object in %s:%d -Stack trace: -#0 {main} - thrown in %s on line %d +--EXPECT-- +object(ArrayIterator)#1 (1) { + ["storage":"ArrayIterator":private]=> + array(2) { + [0]=> + int(1) + [1]=> + &int(1) + } +} +Done