]> granicus.if.org Git - php/commitdiff
Fix SEND_UNPACK array separation
authorNikita Popov <nikic@php.net>
Sat, 16 Apr 2016 20:33:23 +0000 (22:33 +0200)
committerNikita Popov <nikic@php.net>
Sat, 16 Apr 2016 20:33:23 +0000 (22:33 +0200)
Separating only immutable arrays is not enough.

Zend/tests/arg_unpack/by_ref_separation.phpt [new file with mode: 0644]
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/Zend/tests/arg_unpack/by_ref_separation.phpt b/Zend/tests/arg_unpack/by_ref_separation.phpt
new file mode 100644 (file)
index 0000000..b52c281
--- /dev/null
@@ -0,0 +1,36 @@
+--TEST--
+Array must be separated if unpacking by reference
+--FILE--
+<?php
+
+function inc(&... $args) {
+    foreach ($args as &$arg) {
+        $arg++;
+    }
+}
+
+$arr = [1, 2];
+$arr[] = 3;
+$arr2 = $arr;
+inc(...$arr);
+var_dump($arr);
+var_dump($arr2);
+
+?>
+--EXPECT--
+array(3) {
+  [0]=>
+  int(2)
+  [1]=>
+  int(3)
+  [2]=>
+  int(4)
+}
+array(3) {
+  [0]=>
+  int(1)
+  [1]=>
+  int(2)
+  [2]=>
+  int(3)
+}
index 00a9effcfadfca611601195891df294f12a52746..8d01d99ee9a5c11267305dbc29dca687870b5f1e 100644 (file)
@@ -4422,7 +4422,7 @@ ZEND_VM_C_LABEL(send_again):
 
                zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht));
 
-               if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
+               if (OP1_TYPE != IS_CONST && OP1_TYPE != IS_TMP_VAR && Z_REFCOUNT_P(args) > 1) {
                        uint32_t i;
                        int separate = 0;
 
@@ -4434,7 +4434,7 @@ ZEND_VM_C_LABEL(send_again):
                                }
                        }
                        if (separate) {
-                               zval_copy_ctor(args);
+                               SEPARATE_ARRAY(args);
                                ht = Z_ARRVAL_P(args);
                        }
                }
@@ -4448,7 +4448,7 @@ ZEND_VM_C_LABEL(send_again):
 
                        top = ZEND_CALL_ARG(EX(call), arg_num);
                        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
-                               if (!Z_IMMUTABLE_P(args)) {
+                               if (Z_REFCOUNT_P(args) == 1) {
                                        ZVAL_MAKE_REF(arg);
                                        Z_ADDREF_P(arg);
                                        ZVAL_REF(top, Z_REF_P(arg));
index 86dbd0ab3750159c02b1518aed9f8e1427829ffc..592681cd98d077e9239f8e1aff17b10e3ae350d2 100644 (file)
@@ -954,7 +954,7 @@ send_again:
 
                zend_vm_stack_extend_call_frame(&EX(call), arg_num - 1, zend_hash_num_elements(ht));
 
-               if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_IMMUTABLE_P(args)) {
+               if (opline->op1_type != IS_CONST && opline->op1_type != IS_TMP_VAR && Z_REFCOUNT_P(args) > 1) {
                        uint32_t i;
                        int separate = 0;
 
@@ -966,7 +966,7 @@ send_again:
                                }
                        }
                        if (separate) {
-                               zval_copy_ctor(args);
+                               SEPARATE_ARRAY(args);
                                ht = Z_ARRVAL_P(args);
                        }
                }
@@ -980,7 +980,7 @@ send_again:
 
                        top = ZEND_CALL_ARG(EX(call), arg_num);
                        if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
-                               if (!Z_IMMUTABLE_P(args)) {
+                               if (Z_REFCOUNT_P(args) == 1) {
                                        ZVAL_MAKE_REF(arg);
                                        Z_ADDREF_P(arg);
                                        ZVAL_REF(top, Z_REF_P(arg));