From 6b6e666ea4edcc64d98ccca7db3af60c14a06614 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Wed, 8 Feb 2023 15:55:54 +0100 Subject: [PATCH 1/9] Fix another use-after-free with static properties/destructors Also make expression result of assignments consistent, containing the value of the variable from after the destructor has been executed. See GH-10168 --- Zend/tests/gh10168_3.phpt | 3 +-- Zend/zend_execute.c | 7 ++++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index 35c8ed42f847..1275e0995fb9 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -26,5 +26,4 @@ new Test(); --EXPECTF-- object(Test)#1 (0) { } -object(Test)#2 (0) { -} +NULL diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 0d7025b68a64..9e140dde1e1a 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3602,8 +3602,13 @@ ZEND_API zval* zend_assign_to_typed_ref_and_result(zval *variable_ptr, zval *ori ret = zend_verify_ref_assignable_zval(Z_REF_P(variable_ptr), &value, strict); variable_ptr = Z_REFVAL_P(variable_ptr); if (EXPECTED(ret)) { - i_zval_ptr_dtor_noref(variable_ptr); + // The destructor must run after the variable has already been reassigned + // Otherwise, assigning to the variable again can cause a double free + // Thus we need to store the old value in a temporary slot + zval garbage; + ZVAL_COPY_VALUE(&garbage, variable_ptr); ZVAL_COPY_VALUE(variable_ptr, &value); + i_zval_ptr_dtor_noref(&garbage); } else { zval_ptr_dtor_nogc(&value); } From 32635abf3e67b3ca5da31bf07a0510884575f79e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 10 Feb 2023 19:25:58 +0100 Subject: [PATCH 2/9] Fix more potential use-after-free --- Zend/tests/gh10168_1.phpt | 11 +- Zend/tests/gh10168_2.phpt | 9 +- Zend/tests/gh10168_3.phpt | 9 +- Zend/tests/gh10168_4.phpt | 43 ++++ Zend/zend_execute.c | 11 +- Zend/zend_vm_def.h | 22 +- Zend/zend_vm_execute.h | 408 ++++++++++++++++++++++---------------- 7 files changed, 320 insertions(+), 193 deletions(-) create mode 100644 Zend/tests/gh10168_4.phpt diff --git a/Zend/tests/gh10168_1.phpt b/Zend/tests/gh10168_1.phpt index 6433453ed244..5f491ff296db 100644 --- a/Zend/tests/gh10168_1.phpt +++ b/Zend/tests/gh10168_1.phpt @@ -7,7 +7,7 @@ class Test { static $instances; public function __construct() { - (self::$instances[NULL] = $this) > 0; + var_dump(self::$instances[NULL] = $this); var_dump(self::$instances); } @@ -19,14 +19,15 @@ new Test(); new Test(); ?> ---EXPECTF-- -Notice: Object of class Test could not be converted to int in %s on line %d +--EXPECT-- +object(Test)#1 (0) { +} array(1) { [""]=> object(Test)#1 (0) { } } - -Notice: Object of class Test could not be converted to int in %s on line %d +object(Test)#2 (0) { +} array(0) { } diff --git a/Zend/tests/gh10168_2.phpt b/Zend/tests/gh10168_2.phpt index abab8b72f1cb..aa6c0921e279 100644 --- a/Zend/tests/gh10168_2.phpt +++ b/Zend/tests/gh10168_2.phpt @@ -8,7 +8,7 @@ $a = null; class Test { public function __construct() { - ($GLOBALS['a'] = $this) > 0; + var_dump($GLOBALS['a'] = $this); // Destructor called after comparison, so a will be NULL var_dump($GLOBALS['a']); } @@ -22,11 +22,12 @@ new Test(); ?> --EXPECTF-- -Notice: Object of class Test could not be converted to int in %s on line %d object(Test)#1 (0) { } - -Notice: Object of class Test could not be converted to int in %s on line %d +object(Test)#1 (0) { +} +object(Test)#2 (0) { +} Warning: Undefined global variable $a in %s on line %d NULL diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index 1275e0995fb9..36dcb28f5e71 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -9,13 +9,14 @@ class Test public function __construct() { if (self::$a === null) { - var_dump(self::$a = &$this); + var_dump(self::$a = $this); } else { var_dump(self::$a = $this); } } function __destruct() { + var_dump(self::$a); self::$a = null; } } @@ -23,7 +24,11 @@ new Test(); new Test(); ?> ---EXPECTF-- +--EXPECT-- object(Test)#1 (0) { } +object(Test)#2 (0) { +} +object(Test)#2 (0) { +} NULL diff --git a/Zend/tests/gh10168_4.phpt b/Zend/tests/gh10168_4.phpt new file mode 100644 index 000000000000..20ed5ffd3a3e --- /dev/null +++ b/Zend/tests/gh10168_4.phpt @@ -0,0 +1,43 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +--FILE-- +storage = $this); + } else { + var_dump($box->storage = $this); + } + } + + function __destruct() { + global $box; + var_dump($box->storage); + $box->storage = null; + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} +NULL diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 9e140dde1e1a..3b643cd523a5 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -1005,7 +1005,7 @@ ZEND_API bool zend_never_inline zend_verify_property_type(const zend_property_in return i_zend_verify_property_type(info, property, strict); } -static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *info, zval *property_val, zval *value EXECUTE_DATA_DC OPLINE_DC) { zval tmp; @@ -1022,6 +1022,9 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf return &EG(uninitialized_zval); } + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + return zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } @@ -3609,12 +3612,12 @@ ZEND_API zval* zend_assign_to_typed_ref_and_result(zval *variable_ptr, zval *ori ZVAL_COPY_VALUE(&garbage, variable_ptr); ZVAL_COPY_VALUE(variable_ptr, &value); i_zval_ptr_dtor_noref(&garbage); + if (result_variable_ptr) { + ZVAL_COPY_DEREF(result_variable_ptr, &value); + } } else { zval_ptr_dtor_nogc(&value); } - if (result_variable_ptr) { - ZVAL_COPY(result_variable_ptr, variable_ptr); - } if (value_type & (IS_VAR|IS_TMP_VAR)) { if (UNEXPECTED(ref)) { if (UNEXPECTED(GC_DELREF(ref) == 0)) { diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 1785fcfe2a14..c418ee552d16 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2410,13 +2410,15 @@ ZEND_VM_C_LABEL(assign_object): zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - ZEND_VM_C_GOTO(free_and_exit_assign_obj); + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + FREE_OP_DATA(); + ZEND_VM_C_GOTO(exit_assign_obj); } else { ZEND_VM_C_LABEL(fast_assign_obj): - value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); } ZEND_VM_C_GOTO(exit_assign_obj); } @@ -2522,14 +2524,14 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA= value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC OPLINE_CC); FREE_OP_DATA(); } else { - value = zend_assign_to_variable(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + } } /* assign_static_prop has two opcodes! */ diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 00cf2461b91c..20a655170226 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -939,14 +939,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = RT_CONSTANT((opline+1), (opline+1)->op1); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC OPLINE_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CONST, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), prop, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(prop, value, IS_CONST, EX_USES_STRICT_TYPES()); + } } /* assign_static_prop has two opcodes! */ @@ -970,14 +970,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC OPLINE_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { - value = zend_assign_to_variable(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } } /* assign_static_prop has two opcodes! */ @@ -1001,14 +1001,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC OPLINE_CC); zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); } else { - value = zend_assign_to_variable(prop, value, IS_VAR, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), prop, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(prop, value, IS_VAR, EX_USES_STRICT_TYPES()); + } } /* assign_static_prop has two opcodes! */ @@ -1032,14 +1032,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC); + value = zend_assign_to_typed_prop(prop_info, prop, value EXECUTE_DATA_CC OPLINE_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CV, EX_USES_STRICT_TYPES()); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), prop, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(prop, value, IS_CV, EX_USES_STRICT_TYPES()); + } } /* assign_static_prop has two opcodes! */ @@ -23288,13 +23288,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -23418,13 +23420,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -23548,13 +23552,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -23678,13 +23684,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -26164,13 +26172,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -26294,13 +26304,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -26424,13 +26436,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -26554,13 +26568,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -30407,13 +30423,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -30537,13 +30555,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -30667,13 +30687,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -30797,13 +30819,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -33005,13 +33029,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -33135,13 +33161,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -33265,13 +33293,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -33395,13 +33425,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -35023,13 +35055,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -35153,13 +35187,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -35283,13 +35319,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -35413,13 +35451,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -37497,13 +37537,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -37627,13 +37669,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -37757,13 +37801,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -37887,13 +37933,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -41674,13 +41722,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -41804,13 +41854,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -41934,13 +41986,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -42064,13 +42118,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -45481,13 +45537,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -45611,13 +45669,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -45741,13 +45801,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -45871,13 +45933,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -50845,13 +50909,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -50975,13 +51041,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -51105,13 +51173,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } @@ -51235,13 +51305,15 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zend_property_info *prop_info = (zend_property_info*) CACHED_PTR_EX(cache_slot + 2); if (UNEXPECTED(prop_info != NULL)) { - value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - goto free_and_exit_assign_obj; + value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC OPLINE_CC); + + goto exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + value = zend_assign_to_two_variables(EX_VAR(opline->result.var), property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + } else { + value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); } goto exit_assign_obj; } From dff3c6486aef0c46b8a3cbac979a6b675036324e Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 10 Feb 2023 21:27:39 +0100 Subject: [PATCH 3/9] Add leak test --- Zend/tests/gh10168_3.phpt | 2 +- Zend/tests/gh10168_5.phpt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh10168_5.phpt diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index 36dcb28f5e71..04d518925017 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -9,7 +9,7 @@ class Test public function __construct() { if (self::$a === null) { - var_dump(self::$a = $this); + var_dump(self::$a = &$this); } else { var_dump(self::$a = $this); } diff --git a/Zend/tests/gh10168_5.phpt b/Zend/tests/gh10168_5.phpt new file mode 100644 index 000000000000..1d4484376e61 --- /dev/null +++ b/Zend/tests/gh10168_5.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +--FILE-- + +--EXPECT-- +object(Test)#1 (0) { +} +object(Foo)#3 (0) { +} +object(Test)#2 (0) { +} +object(Foo)#1 (0) { +} From 10b21c52fafd4cdc8740560a3da784d94411ed93 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 10 Feb 2023 21:28:58 +0100 Subject: [PATCH 4/9] Fix uninitialized zval --- Zend/zend_execute.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 3b643cd523a5..a9e786c1b792 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -3617,6 +3617,9 @@ ZEND_API zval* zend_assign_to_typed_ref_and_result(zval *variable_ptr, zval *ori } } else { zval_ptr_dtor_nogc(&value); + if (result_variable_ptr) { + ZVAL_UNDEF(result_variable_ptr); + } } if (value_type & (IS_VAR|IS_TMP_VAR)) { if (UNEXPECTED(ref)) { From c3ec022126d788c1a6baa44ff789dba441205fa9 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Fri, 10 Feb 2023 23:10:34 +0100 Subject: [PATCH 5/9] Add test demonstrating write_property problem --- Zend/tests/gh10168_3.phpt | 2 +- Zend/tests/gh10168_4.phpt | 9 +-------- Zend/tests/gh10168_5.phpt | 2 +- Zend/tests/gh10168_6.phpt | 40 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 43 insertions(+), 10 deletions(-) create mode 100644 Zend/tests/gh10168_6.phpt diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index 04d518925017..c87dd52f9806 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -1,5 +1,5 @@ --TEST-- -GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed static prop --XFAIL-- --FILE-- storage = $this); - } else { - var_dump($box->storage = $this); - } + var_dump($box->storage = $this); } function __destruct() { diff --git a/Zend/tests/gh10168_5.phpt b/Zend/tests/gh10168_5.phpt index 1d4484376e61..62e239412b03 100644 --- a/Zend/tests/gh10168_5.phpt +++ b/Zend/tests/gh10168_5.phpt @@ -1,5 +1,5 @@ --TEST-- -GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +GH-10168 (heap-buffer-overflow at zval_undefined_cv): allocated assignment in destructor --FILE-- storage = $this); + } else { + // Avoid cache slot, triggering write_property + var_dump($box->storage = $this); + } + } + + function __destruct() { + global $box; + $box->storage = null; + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} From b7b7ae7f7750440f2d7fe1166050b3b48c98b3f1 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 11 Feb 2023 00:13:46 +0100 Subject: [PATCH 6/9] More tests --- Zend/tests/gh10168_3.phpt | 7 +++++-- Zend/tests/gh10168_4.phpt | 2 +- Zend/tests/gh10168_7.phpt | 31 +++++++++++++++++++++++++++++++ Zend/tests/gh10168_8.phpt | 36 ++++++++++++++++++++++++++++++++++++ 4 files changed, 73 insertions(+), 3 deletions(-) create mode 100644 Zend/tests/gh10168_7.phpt create mode 100644 Zend/tests/gh10168_8.phpt diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index c87dd52f9806..e0f183825802 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -8,9 +8,12 @@ class Test static ?Test $a = null; public function __construct() { - if (self::$a === null) { - var_dump(self::$a = &$this); + static $i = 0; + $i++; + if ($i === 1) { + var_dump(self::$a = $this); } else { + // Avoid cache slot, triggering write_property var_dump(self::$a = $this); } } diff --git a/Zend/tests/gh10168_4.phpt b/Zend/tests/gh10168_4.phpt index 8e519a3362b7..d931a6be9a55 100644 --- a/Zend/tests/gh10168_4.phpt +++ b/Zend/tests/gh10168_4.phpt @@ -1,5 +1,5 @@ --TEST-- -GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign prop --FILE-- +--EXPECT-- +object(Test)#1 (0) { +} +object(Test)#2 (0) { +} +object(Test)#2 (0) { +} +NULL diff --git a/Zend/tests/gh10168_8.phpt b/Zend/tests/gh10168_8.phpt new file mode 100644 index 000000000000..1d626badb1d0 --- /dev/null +++ b/Zend/tests/gh10168_8.phpt @@ -0,0 +1,36 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +--FILE-- +storage = $this); + } + + function __destruct() { + global $box; + var_dump($box->storage); + $box->storage = null; + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} +NULL From 695fe86a3d3cb16a6cae030545ea8c87ea6c3e41 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Sat, 11 Feb 2023 12:57:51 +0100 Subject: [PATCH 7/9] Another test --- Zend/tests/gh10168_9.phpt | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 Zend/tests/gh10168_9.phpt diff --git a/Zend/tests/gh10168_9.phpt b/Zend/tests/gh10168_9.phpt new file mode 100644 index 000000000000..7b427681a8b2 --- /dev/null +++ b/Zend/tests/gh10168_9.phpt @@ -0,0 +1,34 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +--FILE-- +value = $this); + } + + function __destruct() { + global $box; + unset($box->value); + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} From 159884ec8f04b12c7dd306a9c761d364a9eafe08 Mon Sep 17 00:00:00 2001 From: Ilija Tovilo Date: Mon, 13 Feb 2023 13:19:01 +0100 Subject: [PATCH 8/9] More tests --- Zend/tests/gh10168_10.phpt | 21 +++++++++++++++++++++ Zend/tests/gh10168_3.phpt | 1 - 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 Zend/tests/gh10168_10.phpt diff --git a/Zend/tests/gh10168_10.phpt b/Zend/tests/gh10168_10.phpt new file mode 100644 index 000000000000..d44c4800b3d4 --- /dev/null +++ b/Zend/tests/gh10168_10.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +--FILE-- + +--EXPECT-- \ No newline at end of file diff --git a/Zend/tests/gh10168_3.phpt b/Zend/tests/gh10168_3.phpt index e0f183825802..651ff9077e1d 100644 --- a/Zend/tests/gh10168_3.phpt +++ b/Zend/tests/gh10168_3.phpt @@ -1,6 +1,5 @@ --TEST-- GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed static prop ---XFAIL-- --FILE-- Date: Tue, 14 Feb 2023 00:02:48 +0100 Subject: [PATCH 9/9] Fix more reference issues --- Zend/tests/gh10168_10.phpt | 13 ++++---- Zend/tests/gh10168_11.phpt | 21 ++++++++++++ Zend/tests/gh10168_12.phpt | 22 +++++++++++++ Zend/tests/gh10168_13.phpt | 35 ++++++++++++++++++++ Zend/tests/gh10168_14.phpt | 35 ++++++++++++++++++++ Zend/tests/gh10168_15.phpt | 21 ++++++++++++ Zend/tests/gh10168_7.phpt | 4 +-- Zend/zend_execute.c | 54 ++++++++++++++++++++----------- Zend/zend_vm_def.h | 26 +++++++-------- Zend/zend_vm_execute.h | 65 +++++++++++++++++--------------------- 10 files changed, 218 insertions(+), 78 deletions(-) create mode 100644 Zend/tests/gh10168_11.phpt create mode 100644 Zend/tests/gh10168_12.phpt create mode 100644 Zend/tests/gh10168_13.phpt create mode 100644 Zend/tests/gh10168_14.phpt create mode 100644 Zend/tests/gh10168_15.phpt diff --git a/Zend/tests/gh10168_10.phpt b/Zend/tests/gh10168_10.phpt index d44c4800b3d4..38b81bd9e9ba 100644 --- a/Zend/tests/gh10168_10.phpt +++ b/Zend/tests/gh10168_10.phpt @@ -1,16 +1,14 @@ --TEST-- -GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed static prop ref --FILE-- ---EXPECT-- \ No newline at end of file +--EXPECT-- +object(Test)#1 (0) { +} +NULL diff --git a/Zend/tests/gh10168_11.phpt b/Zend/tests/gh10168_11.phpt new file mode 100644 index 000000000000..3afcd7727e7e --- /dev/null +++ b/Zend/tests/gh10168_11.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): global by ref val error +--FILE-- + +--EXPECTF-- +Notice: Only variables should be assigned by reference in %s on line %d +int(42) diff --git a/Zend/tests/gh10168_12.phpt b/Zend/tests/gh10168_12.phpt new file mode 100644 index 000000000000..36400f90b549 --- /dev/null +++ b/Zend/tests/gh10168_12.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign static prop ref +--FILE-- + +--EXPECT-- +object(Test)#1 (0) { +} +NULL diff --git a/Zend/tests/gh10168_13.phpt b/Zend/tests/gh10168_13.phpt new file mode 100644 index 000000000000..94f7d67d6443 --- /dev/null +++ b/Zend/tests/gh10168_13.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign prop ref +--FILE-- +storage = &$this); + } + + function __destruct() { + global $box; + var_dump($box->storage); + $box->storage = null; + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} +NULL +NULL diff --git a/Zend/tests/gh10168_14.phpt b/Zend/tests/gh10168_14.phpt new file mode 100644 index 000000000000..62c4f0e9b93e --- /dev/null +++ b/Zend/tests/gh10168_14.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed prop ref +--FILE-- +storage = &$this); + } + + function __destruct() { + global $box; + var_dump($box->storage); + $box->storage = null; + } +} +new Test(); +new Test(); + +?> +--EXPECT-- +object(Test)#2 (0) { +} +object(Test)#3 (0) { +} +NULL +NULL diff --git a/Zend/tests/gh10168_15.phpt b/Zend/tests/gh10168_15.phpt new file mode 100644 index 000000000000..4185f352d460 --- /dev/null +++ b/Zend/tests/gh10168_15.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168 (heap-buffer-overflow at zval_undefined_cv): global by ref +--FILE-- + +--EXPECT-- +int(42) diff --git a/Zend/tests/gh10168_7.phpt b/Zend/tests/gh10168_7.phpt index 645809df504b..d0ab5dfc2907 100644 --- a/Zend/tests/gh10168_7.phpt +++ b/Zend/tests/gh10168_7.phpt @@ -1,6 +1,5 @@ --TEST-- GH-10168 (heap-buffer-overflow at zval_undefined_cv): assign typed static prop by ref ---XFAIL-- --FILE-- result.var) : NULL; + if (EXPECTED(Z_TYPE_P(variable_ptr) == IS_INDIRECT)) { variable_ptr = Z_INDIRECT_P(variable_ptr); if (/*OP_DATA_TYPE == IS_VAR &&*/ (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( - variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); + variable_ptr = zend_wrong_assign_to_variable_reference(result_ptr, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { zend_property_info *prop_info = NULL; @@ -3270,21 +3288,21 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container } if (UNEXPECTED(prop_info)) { - variable_ptr = zend_assign_to_typed_property_reference(prop_info, variable_ptr, value_ptr EXECUTE_DATA_CC); + variable_ptr = zend_assign_to_typed_property_reference(prop_info, result_ptr, variable_ptr, value_ptr EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(result_ptr, variable_ptr, value_ptr); } } } else if (Z_ISERROR_P(variable_ptr)) { - variable_ptr = &EG(uninitialized_zval); + if (result_ptr) { + ZVAL_COPY(result_ptr, &EG(uninitialized_zval)); + } } else { zend_throw_error(NULL, "Cannot assign by reference to overloaded object"); zval_ptr_dtor(&variable); - variable_ptr = &EG(uninitialized_zval); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + if (result_ptr) { + ZVAL_COPY(result_ptr, &EG(uninitialized_zval)); + } } } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index c418ee552d16..42fcfd54c22f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2727,19 +2727,18 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); - variable_ptr = &EG(uninitialized_zval); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), &EG(uninitialized_zval)); + } } else if (OP2_TYPE == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( + zend_wrong_assign_to_variable_reference( + UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + zend_assign_to_variable_reference(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr); } FREE_OP2(); @@ -2787,7 +2786,7 @@ ZEND_VM_HANDLER(32, ZEND_ASSIGN_OBJ_REF, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CA ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) { USE_OPLINE - zval *prop, *value_ptr; + zval *prop, *value_ptr, *result_ptr; zend_property_info *prop_info; SAVE_OPLINE(); @@ -2799,19 +2798,16 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) } value_ptr = GET_OP_DATA_ZVAL_PTR_PTR(BP_VAR_W); + result_ptr = UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL; if (OP_DATA_TYPE == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(result_ptr, prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { prop = &EG(uninitialized_zval); } } else if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC); + prop = zend_assign_to_typed_property_reference(prop_info, result_ptr, prop, value_ptr EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), prop); + zend_assign_to_variable_reference(result_ptr, prop, value_ptr); } FREE_OP_DATA(); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 20a655170226..8a21ff319a76 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1049,7 +1049,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE - zval *prop, *value_ptr; + zval *prop, *value_ptr, *result_ptr; zend_property_info *prop_info; SAVE_OPLINE(); @@ -1061,19 +1061,16 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA } value_ptr = get_zval_ptr_ptr((opline+1)->op1_type, (opline+1)->op1, BP_VAR_W); + result_ptr = UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL; if ((opline+1)->op1_type == IS_VAR && (opline->extended_value & ZEND_RETURNS_FUNCTION) && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { + if (UNEXPECTED(!zend_wrong_assign_to_variable_reference(result_ptr, prop, value_ptr OPLINE_CC EXECUTE_DATA_CC))) { prop = &EG(uninitialized_zval); } } else if (UNEXPECTED(ZEND_TYPE_IS_SET(prop_info->type))) { - prop = zend_assign_to_typed_property_reference(prop_info, prop, value_ptr EXECUTE_DATA_CC); + prop = zend_assign_to_typed_property_reference(prop_info, result_ptr, prop, value_ptr EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), prop); + zend_assign_to_variable_reference(result_ptr, prop, value_ptr); } FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); @@ -28051,19 +28048,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLE UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); - variable_ptr = &EG(uninitialized_zval); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), &EG(uninitialized_zval)); + } } else if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( + zend_wrong_assign_to_variable_reference( + UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + zend_assign_to_variable_reference(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -31584,19 +31580,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); - variable_ptr = &EG(uninitialized_zval); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), &EG(uninitialized_zval)); + } } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( + zend_wrong_assign_to_variable_reference( + UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + zend_assign_to_variable_reference(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); @@ -47691,19 +47686,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); - variable_ptr = &EG(uninitialized_zval); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), &EG(uninitialized_zval)); + } } else if (IS_VAR == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( + zend_wrong_assign_to_variable_reference( + UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + zend_assign_to_variable_reference(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr); } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); @@ -52068,19 +52062,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER( UNEXPECTED(Z_TYPE_P(EX_VAR(opline->op1.var)) != IS_INDIRECT)) { zend_throw_error(NULL, "Cannot assign by reference to an array dimension of an object"); - variable_ptr = &EG(uninitialized_zval); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), &EG(uninitialized_zval)); + } } else if (IS_CV == IS_VAR && opline->extended_value == ZEND_RETURNS_FUNCTION && UNEXPECTED(!Z_ISREF_P(value_ptr))) { - variable_ptr = zend_wrong_assign_to_variable_reference( + zend_wrong_assign_to_variable_reference( + UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); - } - - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); + zend_assign_to_variable_reference(UNEXPECTED(RETURN_VALUE_USED(opline)) ? EX_VAR(opline->result.var) : NULL, variable_ptr, value_ptr); }