]> granicus.if.org Git - php/commitdiff
Support references in convert_to_*
authorNikita Popov <nikic@php.net>
Tue, 16 Jun 2015 17:55:33 +0000 (19:55 +0200)
committerNikita Popov <nikic@php.net>
Tue, 16 Jun 2015 17:55:33 +0000 (19:55 +0200)
conver_to_* functions now accept REFERENCE values, which will be
unwrapped before performing the usual conversion. This is consistent
with convert_scalar_to_number and matches the expected behavior in
a couple random use-sites I checked.

Also includes a couple fixes/cleanups elsewhere and two tests for
cases that previously didn't work (though the reference issue existed
all over the place).

Zend/zend_operators.c
ext/spl/spl_heap.c
ext/spl/spl_iterators.c
ext/spl/tests/RegexIterator_with_reference_replacement.phpt [new file with mode: 0644]
ext/spl/tests/SplHeap_with_by_reference_compare.phpt [new file with mode: 0644]
ext/standard/array.c

index 3176cb505b7d1001216260001b782031a0628d8d..d7d25913823e21076c48d7255310b161e467696e 100644 (file)
@@ -135,17 +135,23 @@ ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, int str_len) /* {{{
 }
 /* }}} */
 
+static zend_always_inline void zend_unwrap_reference(zval *op) /* {{{ */
+{
+       if (Z_REFCOUNT_P(op) == 1) {
+               ZVAL_UNREF(op);
+       } else {
+               Z_DELREF_P(op);
+               ZVAL_COPY(op, Z_REFVAL_P(op));
+       }
+}
+/* }}} */
+
 ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
 {
 try_again:
        switch (Z_TYPE_P(op)) {
                case IS_REFERENCE:
-                       if (Z_REFCOUNT_P(op) == 1) {
-                               ZVAL_UNREF(op);
-                       } else {
-                               Z_DELREF_P(op);
-                               ZVAL_COPY(op, Z_REFVAL_P(op));
-                       }
+                       zend_unwrap_reference(op);
                        goto try_again;
                case IS_STRING:
                        {
@@ -284,6 +290,7 @@ ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
 {
        zend_long tmp;
 
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_NULL:
                case IS_FALSE:
@@ -331,6 +338,9 @@ ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
                                }
                                return;
                        }
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
@@ -340,6 +350,7 @@ ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
 {
        double tmp;
 
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_NULL:
                case IS_FALSE:
@@ -388,6 +399,9 @@ ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
                                }
                                break;
                        }
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
@@ -417,6 +431,7 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
 {
        int tmp;
 
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_FALSE:
                case IS_TRUE:
@@ -469,6 +484,9 @@ ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
                                }
                                break;
                        }
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
@@ -482,6 +500,7 @@ ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op ZEND_FILE_LINE_DC) /* {
 
 ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{{ */
 {
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_UNDEF:
                case IS_NULL:
@@ -534,6 +553,9 @@ ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op ZEND_FILE_LINE_DC) /* {{
                        }
                        break;
                }
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                EMPTY_SWITCH_DEFAULT_CASE()
        }
 }
@@ -553,7 +575,7 @@ static void convert_scalar_to_array(zval *op) /* {{{ */
 
 ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
 {
-
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_ARRAY:
                        break;
@@ -590,6 +612,9 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
                        ZVAL_NEW_ARR(op);
                        zend_hash_init(Z_ARRVAL_P(op), 8, NULL, ZVAL_PTR_DTOR, 0);
                        break;
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                default:
                        convert_scalar_to_array(op);
                        break;
@@ -599,7 +624,7 @@ ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
 
 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
 {
-
+try_again:
        switch (Z_TYPE_P(op)) {
                case IS_ARRAY:
                        {
@@ -614,6 +639,9 @@ ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
                case IS_NULL:
                        object_init(op);
                        break;
+               case IS_REFERENCE:
+                       zend_unwrap_reference(op);
+                       goto try_again;
                default: {
                        zval tmp;
                        ZVAL_COPY_VALUE(&tmp, op);
index c4857663e76d0d50ca6f7c315e642fd7e7ff061c..1d8cde25fa89d3fbb8c7f2c2029e47d83435271c 100644 (file)
@@ -112,9 +112,7 @@ static int spl_ptr_heap_cmp_cb_helper(zval *object, spl_heap_object *heap_object
                return FAILURE;
        }
 
-       convert_to_long(&zresult);
-       *result = Z_LVAL(zresult);
-
+       *result = zval_get_long(&zresult);
        zval_ptr_dtor(&zresult);
 
        return SUCCESS;
index aa0854ab78f77e95aed368c5ed656a336fb3885d..ed325a18806afc993f942c2d464992a476df1c84 100644 (file)
@@ -1065,12 +1065,12 @@ static void spl_recursive_tree_iterator_get_entry(spl_recursive_it_object *objec
         * without __toString is converted to string is converted into an exception. */
        zend_replace_error_handling(EH_THROW, spl_ce_UnexpectedValueException, &error_handling);
        if (data) {
-               RETVAL_ZVAL(data, 1, 0);
-               if (Z_TYPE_P(return_value) == IS_ARRAY) {
-                       zval_ptr_dtor(return_value);
+               ZVAL_DEREF(data);
+               if (Z_TYPE_P(data) == IS_ARRAY) {
                        ZVAL_STRINGL(return_value, "Array", sizeof("Array")-1);
                } else {
-                       convert_to_string_ex(return_value);
+                       ZVAL_COPY(return_value, data);
+                       convert_to_string(return_value);
                }
        }
        zend_restore_error_handling(&error_handling);
diff --git a/ext/spl/tests/RegexIterator_with_reference_replacement.phpt b/ext/spl/tests/RegexIterator_with_reference_replacement.phpt
new file mode 100644 (file)
index 0000000..18b3ef9
--- /dev/null
@@ -0,0 +1,19 @@
+--TEST--
+RegexIterator with $replacement being a reference
+--FILE--
+<?php
+$a = new ArrayIterator(array('test1', 'test2', 'test3'));
+$i = new RegexIterator($a, '/^(test)(\d+)/', RegexIterator::REPLACE);
+$r = '$2:$1';
+$i->replacement =& $r;
+var_dump(iterator_to_array($i));
+?>
+--EXPECT--
+array(3) {
+  [0]=>
+  string(6) "1:test"
+  [1]=>
+  string(6) "2:test"
+  [2]=>
+  string(6) "3:test"
+}
diff --git a/ext/spl/tests/SplHeap_with_by_reference_compare.phpt b/ext/spl/tests/SplHeap_with_by_reference_compare.phpt
new file mode 100644 (file)
index 0000000..b7b7b6d
--- /dev/null
@@ -0,0 +1,16 @@
+--TEST--
+SplHeap using a compare function returning by-reference
+--FILE--
+<?php
+class Heap extends SplMinHeap {
+    public function &compare($a, $b) {
+        return $a;
+    }
+}
+$h = new Heap;
+$h->insert(0);
+$h->insert(0);
+?>
+===DONE===
+--EXPECT--
+===DONE===
index b05900656d6b3f334b2f0c7f575f991cc1a0640d..527f6a3df1f265117efea0c4d3b121c560460b8c 100644 (file)
@@ -3099,17 +3099,15 @@ PHP_FUNCTION(array_column)
                        zkeyval = zend_hash_index_find(ht, Z_LVAL_P(zkey));
                }
 
-               if (Z_REFCOUNTED_P(zcolval)) {
-                       Z_ADDREF_P(zcolval);
-               }
+               Z_TRY_ADDREF_P(zcolval);
                if (zkeyval && Z_TYPE_P(zkeyval) == IS_STRING) {
                        zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(zkeyval), zcolval);
                } else if (zkeyval && Z_TYPE_P(zkeyval) == IS_LONG) {
                        add_index_zval(return_value, Z_LVAL_P(zkeyval), zcolval);
                } else if (zkeyval && Z_TYPE_P(zkeyval) == IS_OBJECT) {
-                       SEPARATE_ZVAL(zkeyval);
-                       convert_to_string(zkeyval);
-                       zend_symtable_update(Z_ARRVAL_P(return_value), Z_STR_P(zkeyval), zcolval);
+                       zend_string *key = zval_get_string(zkeyval);
+                       zend_symtable_update(Z_ARRVAL_P(return_value), key, zcolval);
+                       zend_string_release(key);
                } else {
                        add_next_index_zval(return_value, zcolval);
                }