From: Dmitry Stogov Date: Tue, 7 Jun 2016 20:18:52 +0000 (+0300) Subject: Fixed bug #71266 (Missing separation of properties HT in foreach etc). X-Git-Tag: php-7.1.0alpha3~42^2~52 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=421843977f3f2f65c2e7d6d2827b322a54042422;p=php Fixed bug #71266 (Missing separation of properties HT in foreach etc). --- diff --git a/NEWS b/NEWS index f1cc6da293..a97fb14b03 100644 --- 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 index 0000000000..d67c6f6363 --- /dev/null +++ b/Zend/tests/bug71266.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #71266 (Missing separation of properties HT in foreach etc) +--FILE-- + $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) diff --git a/Zend/zend_API.c b/Zend/zend_API.c index eb76c671fc..18d8382934 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -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"; } } diff --git a/Zend/zend_API.h b/Zend/zend_API.h index ff93a53139..85ae8b91d4 100644 --- a/Zend/zend_API.h +++ b/Zend/zend_API.h @@ -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; diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2ec5c80bec..5922275762 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -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) { diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f7bc9fb454..4b0454b0e0 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -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) {