]> granicus.if.org Git - php/commitdiff
Fixed bug #71266 (Missing separation of properties HT in foreach etc).
authorDmitry Stogov <dmitry@zend.com>
Tue, 7 Jun 2016 20:18:52 +0000 (23:18 +0300)
committerDmitry Stogov <dmitry@zend.com>
Tue, 7 Jun 2016 20:18:52 +0000 (23:18 +0300)
NEWS
Zend/tests/bug71266.phpt [new file with mode: 0644]
Zend/zend_API.c
Zend/zend_API.h
Zend/zend_vm_def.h
Zend/zend_vm_execute.h

diff --git a/NEWS b/NEWS
index f1cc6da293e029101ecd6cbd5cb086d1340c03d4..a97fb14b03bf786c44fbe63cdff7c093522796fb 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -20,6 +20,8 @@ PHP                                                                        NEWS
   . Fixed bug #62814 (It is possible to stiffen child class members visibility).
     (Nikita)
   . Fixed bug #69989 (Generators don't participate in cycle GC). (Nikita)
+  . Fixed bug #71266 (Missing separation of properties HT in foreach etc).
+    (Dmitry)
   . Fixed bug #71604 (Aborted Generators continue after nested finally).
     (Nikita)
   . Fixed bug #71572 (String offset assignment from an empty string inserts
diff --git a/Zend/tests/bug71266.phpt b/Zend/tests/bug71266.phpt
new file mode 100644 (file)
index 0000000..d67c6f6
--- /dev/null
@@ -0,0 +1,22 @@
+--TEST--
+Bug #71266 (Missing separation of properties HT in foreach etc)
+--FILE--
+<?php
+$one = 1;
+$two = 2;
+$arr = ['foo' => $one, 'bar' => $two];
+$obj = (object) $arr;
+foreach ($obj as $val) {
+    var_dump($val);
+    $obj->bar = 42;
+}
+
+$arr = ['foo' => $one, 'bar' => $two];
+$obj = (object) $arr;
+next($obj);
+var_dump(current($arr));
+?>
+--EXPECT--
+int(1)
+int(42)
+int(1)
index eb76c671fc0f59148802fe8b0fc08624cd2cd8a6..18d83829340789a1a0780c9c685b82e4cc33de06 100644 (file)
@@ -495,6 +495,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
        const char *spec_walk = *spec;
        char c = *spec_walk++;
        int check_null = 0;
+       int separate = 0;
        zval *real_arg = arg;
 
        /* scan through modifiers */
@@ -503,6 +504,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
                if (*spec_walk == '/') {
                        SEPARATE_ZVAL_NOREF(arg);
                        real_arg = arg;
+                       separate = 1;
                } else if (*spec_walk == '!') {
                        check_null = 1;
                } else {
@@ -622,7 +624,7 @@ static const char *zend_parse_arg_impl(int arg_num, zval *arg, va_list *va, cons
                        {
                                HashTable **p = va_arg(*va, HashTable **);
 
-                               if (!zend_parse_arg_array_ht(arg, p, check_null, c == 'H')) {
+                               if (!zend_parse_arg_array_ht(arg, p, check_null, c == 'H', separate)) {
                                        return "array";
                                }
                        }
index ff93a53139ffeae113f2eb12a15fb062c79964ea..85ae8b91d467002afd47a0f01c13080c69d310c8 100644 (file)
@@ -862,7 +862,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, in
 /* old "h" */
 #define Z_PARAM_ARRAY_HT_EX(dest, check_null, separate) \
                Z_PARAM_PROLOGUE(separate); \
-               if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 0))) { \
+               if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 0, separate))) { \
                        _expected_type = Z_EXPECTED_ARRAY; \
                        error_code = ZPP_ERROR_WRONG_ARG; \
                        break; \
@@ -874,7 +874,7 @@ ZEND_API ZEND_COLD void ZEND_FASTCALL zend_wrong_callback_error(int severity, in
 /* old "H" */
 #define Z_PARAM_ARRAY_OR_OBJECT_HT_EX(dest, check_null, separate) \
                Z_PARAM_PROLOGUE(separate); \
-               if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 1))) { \
+               if (UNEXPECTED(!zend_parse_arg_array_ht(_arg, &dest, check_null, 1, separate))) { \
                        _expected_type = Z_EXPECTED_ARRAY; \
                        error_code = ZPP_ERROR_WRONG_ARG; \
                        break; \
@@ -1177,11 +1177,19 @@ static zend_always_inline int zend_parse_arg_array(zval *arg, zval **dest, int c
        return 1;
 }
 
-static zend_always_inline int zend_parse_arg_array_ht(zval *arg, HashTable **dest, int check_null, int or_object)
+static zend_always_inline int zend_parse_arg_array_ht(zval *arg, HashTable **dest, int check_null, int or_object, int separate)
 {
        if (EXPECTED(Z_TYPE_P(arg) == IS_ARRAY)) {
                *dest = Z_ARRVAL_P(arg);
        } else if (or_object && EXPECTED(Z_TYPE_P(arg) == IS_OBJECT)) {
+               if (separate
+                && Z_OBJ_P(arg)->properties
+                && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(arg)->properties) > 1)) {
+                       if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(arg)->properties) & IS_ARRAY_IMMUTABLE))) {
+                               GC_REFCOUNT(Z_OBJ_P(arg)->properties)--;
+                       }
+                       Z_OBJ_P(arg)->properties = zend_array_dup(Z_OBJ_P(arg)->properties);
+               }
                *dest = Z_OBJ_HT_P(arg)->get_properties(arg);
        } else if (check_null && EXPECTED(Z_TYPE_P(arg) == IS_NULL)) {
                *dest = NULL;
index 2ec5c80bec1f841e51cb11762be6b6510b4b927f..5922275762b67198ac813fc162b481c301e51a28 100644 (file)
@@ -5742,6 +5742,13 @@ ZEND_VM_HANDLER(77, ZEND_FE_RESET_R, CONST|TMP|VAR|CV, JMP_ADDR)
                        if (OP1_TYPE != IS_TMP_VAR) {
                                Z_ADDREF_P(array_ptr);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        pos = 0;
                        p = fe_ht->arData;
@@ -5888,6 +5895,13 @@ ZEND_VM_HANDLER(125, ZEND_FE_RESET_RW, CONST|TMP|VAR|CV, JMP_ADDR)
                                array_ptr = EX_VAR(opline->result.var);
                                ZVAL_COPY_VALUE(array_ptr, array_ref);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        p = fe_ht->arData;
                        while (1) {
index f7bc9fb454070e3a2ef03b3323d2825509433d5a..4b0454b0e0c251677c059018561419ffd8ea56c2 100644 (file)
@@ -3441,6 +3441,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CONST_HANDLER(
                        if (IS_CONST != IS_TMP_VAR) {
                                Z_ADDREF_P(array_ptr);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        pos = 0;
                        p = fe_ht->arData;
@@ -3584,6 +3591,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CONST_HANDLER
                                array_ptr = EX_VAR(opline->result.var);
                                ZVAL_COPY_VALUE(array_ptr, array_ref);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        p = fe_ht->arData;
                        while (1) {
@@ -12503,6 +12517,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_TMP_HANDLER(ZE
                        if (IS_TMP_VAR != IS_TMP_VAR) {
                                Z_ADDREF_P(array_ptr);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        pos = 0;
                        p = fe_ht->arData;
@@ -12647,6 +12668,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_TMP_HANDLER(Z
                                array_ptr = EX_VAR(opline->result.var);
                                ZVAL_COPY_VALUE(array_ptr, array_ref);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        p = fe_ht->arData;
                        while (1) {
@@ -16071,6 +16099,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_VAR_HANDLER(ZE
                        if (IS_VAR != IS_TMP_VAR) {
                                Z_ADDREF_P(array_ptr);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        pos = 0;
                        p = fe_ht->arData;
@@ -16217,6 +16252,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_VAR_HANDLER(Z
                                array_ptr = EX_VAR(opline->result.var);
                                ZVAL_COPY_VALUE(array_ptr, array_ref);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        p = fe_ht->arData;
                        while (1) {
@@ -37831,6 +37873,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_R_SPEC_CV_HANDLER(ZEN
                        if (IS_CV != IS_TMP_VAR) {
                                Z_ADDREF_P(array_ptr);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        pos = 0;
                        p = fe_ht->arData;
@@ -37974,6 +38023,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_FE_RESET_RW_SPEC_CV_HANDLER(ZE
                                array_ptr = EX_VAR(opline->result.var);
                                ZVAL_COPY_VALUE(array_ptr, array_ref);
                        }
+                       if (Z_OBJ_P(array_ptr)->properties
+                        && UNEXPECTED(GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties) > 1)) {
+                               if (EXPECTED(!(GC_FLAGS(Z_OBJ_P(array_ptr)->properties) & IS_ARRAY_IMMUTABLE))) {
+                                       GC_REFCOUNT(Z_OBJ_P(array_ptr)->properties)--;
+                               }
+                               Z_OBJ_P(array_ptr)->properties = zend_array_dup(Z_OBJ_P(array_ptr)->properties);
+                       }
                        fe_ht = Z_OBJPROP_P(array_ptr);
                        p = fe_ht->arData;
                        while (1) {