diff --git a/Zend/tests/gh10168/assign.phpt b/Zend/tests/gh10168/assign.phpt new file mode 100644 index 0000000000000..3c6740165d4a4 --- /dev/null +++ b/Zend/tests/gh10168/assign.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim.phpt b/Zend/tests/gh10168/assign_dim.phpt new file mode 100644 index 0000000000000..1a31cfdde3b7d --- /dev/null +++ b/Zend/tests/gh10168/assign_dim.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign dim +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_ref.phpt b/Zend/tests/gh10168/assign_dim_ref.phpt new file mode 100644 index 0000000000000..40ae4485d2cfb --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_ref.phpt @@ -0,0 +1,19 @@ +--TEST-- +GH-10168: Assign dim ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..8415df433686a --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_ref_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign dim ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt b/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt new file mode 100644 index 0000000000000..764d10d34658b --- /dev/null +++ b/Zend/tests/gh10168/assign_dim_with_prop_ref.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Assign dim with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop.phpt b/Zend/tests/gh10168/assign_prop.phpt new file mode 100644 index 0000000000000..ad7bb762f555b --- /dev/null +++ b/Zend/tests/gh10168/assign_prop.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref.phpt new file mode 100644 index 0000000000000..606542fbd6c6d --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_ref.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +NULL +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..f887acbc1d06e --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_ref_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop ref with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +NULL diff --git a/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..a08386e74565c --- /dev/null +++ b/Zend/tests/gh10168/assign_prop_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_ref.phpt b/Zend/tests/gh10168/assign_ref.phpt new file mode 100644 index 0000000000000..9f3be5619d1ae --- /dev/null +++ b/Zend/tests/gh10168/assign_ref.phpt @@ -0,0 +1,18 @@ +--TEST-- +GH-10168: Assign ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..42ce94b3f83e1 --- /dev/null +++ b/Zend/tests/gh10168/assign_ref_with_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign ref with prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_prop.phpt b/Zend/tests/gh10168/assign_static_prop.phpt new file mode 100644 index 0000000000000..900a69ae40aa5 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_ref.phpt new file mode 100644 index 0000000000000..2e90be884dedd --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..df11b17e27819 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_ref_with_prop_ref.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10168: Assign static prop ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..c98233589c41f --- /dev/null +++ b/Zend/tests/gh10168/assign_static_prop_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign static prop with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop.phpt b/Zend/tests/gh10168/assign_static_untyped_prop.phpt new file mode 100644 index 0000000000000..cf1736b6c58df --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt new file mode 100644 index 0000000000000..dfef8ead26f6e --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_ref.phpt @@ -0,0 +1,20 @@ +--TEST-- +GH-10168: Assign static prop ref +--FILE-- + +--EXPECT-- +NULL diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..337c9a8f1475f --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_ref_with_prop_ref.phpt @@ -0,0 +1,23 @@ +--TEST-- +GH-10168: Assign static prop ref with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..1b46cafaa0407 --- /dev/null +++ b/Zend/tests/gh10168/assign_static_untyped_prop_with_prop_ref.phpt @@ -0,0 +1,22 @@ +--TEST-- +GH-10168: Assign static prop with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop.phpt b/Zend/tests/gh10168/assign_untyped_prop.phpt new file mode 100644 index 0000000000000..b13df3afbd87f --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt new file mode 100644 index 0000000000000..a28395d43bbbc --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_ref.phpt @@ -0,0 +1,32 @@ +--TEST-- +GH-10168: Assign prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +NULL +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt new file mode 100644 index 0000000000000..79ff5fefc07ed --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_ref_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop ref with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + $tmp = new Test; + var_dump($box->value = &$tmp); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +NULL diff --git a/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt b/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt new file mode 100644 index 0000000000000..7e77ddf7da83f --- /dev/null +++ b/Zend/tests/gh10168/assign_untyped_prop_with_prop_ref.phpt @@ -0,0 +1,35 @@ +--TEST-- +GH-10168: Assign prop with prop ref +--FILE-- +value = null; + } +} + +function test($box) { + var_dump($box->value = new Test); +} + +$box = new Box(); +$box->value = new Test; +Test::$test = &$box->value; +test($box); +// Second call tests the cache slot path +test($box); + +?> +--EXPECT-- +object(Test)#3 (0) { +} +object(Test)#3 (0) { +} diff --git a/Zend/tests/gh10168/assign_with_prop_ref.phpt b/Zend/tests/gh10168/assign_with_prop_ref.phpt new file mode 100644 index 0000000000000..f3e8756514502 --- /dev/null +++ b/Zend/tests/gh10168/assign_with_prop_ref.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Assign with prop ref +--FILE-- + +--EXPECT-- +object(Test)#2 (0) { +} diff --git a/Zend/tests/gh10168/wrong_assign_to_variable.phpt b/Zend/tests/gh10168/wrong_assign_to_variable.phpt new file mode 100644 index 0000000000000..36fdecdfefcd5 --- /dev/null +++ b/Zend/tests/gh10168/wrong_assign_to_variable.phpt @@ -0,0 +1,21 @@ +--TEST-- +GH-10168: Wrong assign to variable +--FILE-- + +--EXPECTF-- +Notice: Only variables should be assigned by reference in %s on line %d +int(42) diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index abe3b8042c96e..8384e5959dead 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -546,7 +546,7 @@ static inline ZEND_ATTRIBUTE_UNUSED zval *_get_obj_zval_ptr_ptr(int op_type, zno return get_zval_ptr_ptr(op_type, node, type); } -static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr) +static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr, zend_refcounted **garbage_ptr) { zend_reference *ref; @@ -559,20 +559,12 @@ static inline void zend_assign_to_variable_reference(zval *variable_ptr, zval *v ref = Z_REF_P(value_ptr); GC_ADDREF(ref); if (Z_REFCOUNTED_P(variable_ptr)) { - zend_refcounted *garbage = Z_COUNTED_P(variable_ptr); - - if (GC_DELREF(garbage) == 0) { - ZVAL_REF(variable_ptr, ref); - rc_dtor_func(garbage); - return; - } else { - gc_check_possible_root(garbage); - } + *garbage_ptr = Z_COUNTED_P(variable_ptr); } ZVAL_REF(variable_ptr, ref); } -static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_property_info *prop_info, zval *prop, zval *value_ptr EXECUTE_DATA_DC) +static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_property_info *prop_info, zval *prop, zval *value_ptr, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) { if (!zend_verify_prop_assignable_by_ref(prop_info, value_ptr, EX_USES_STRICT_TYPES())) { return &EG(uninitialized_zval); @@ -580,12 +572,12 @@ static zend_never_inline zval* zend_assign_to_typed_property_reference(zend_prop if (Z_ISREF_P(prop)) { ZEND_REF_DEL_TYPE_SOURCE(Z_REF_P(prop), prop_info); } - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, garbage_ptr); ZEND_REF_ADD_TYPE_SOURCE(Z_REF_P(prop), prop_info); return prop; } -static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) +static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference(zval *variable_ptr, zval *value_ptr, zend_refcounted **garbage_ptr OPLINE_DC EXECUTE_DATA_DC) { zend_error(E_NOTICE, "Only variables should be assigned by reference"); if (UNEXPECTED(EG(exception) != NULL)) { @@ -594,7 +586,7 @@ static zend_never_inline ZEND_COLD zval *zend_wrong_assign_to_variable_reference /* Use IS_TMP_VAR instead of IS_VAR to avoid ISREF check */ Z_TRY_ADDREF_P(value_ptr); - return zend_assign_to_variable(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + return zend_assign_to_variable_ex(variable_ptr, value_ptr, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } ZEND_API ZEND_COLD void ZEND_FASTCALL zend_cannot_pass_by_reference(uint32_t arg_num) @@ -957,7 +949,7 @@ static bool zend_check_and_resolve_property_class_type( if (zend_check_intersection_for_property_class_type( ZEND_TYPE_LIST(*list_type), info, object_ce)) { return true; - } + } continue; } ZEND_ASSERT(!ZEND_TYPE_HAS_LIST(*list_type)); @@ -1005,7 +997,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, zend_refcounted **garbage_ptr EXECUTE_DATA_DC) { zval tmp; @@ -1024,7 +1016,7 @@ static zend_never_inline zval* zend_assign_to_typed_prop(zend_property_info *inf Z_PROP_FLAG_P(property_val) &= ~IS_PROP_REINITABLE; - return zend_assign_to_variable(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + return zend_assign_to_variable_ex(property_val, &tmp, IS_TMP_VAR, EX_USES_STRICT_TYPES(), garbage_ptr); } static zend_always_inline bool zend_value_instanceof_static(zval *zv) { @@ -3248,6 +3240,7 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container { zval variable, *variable_ptr = &variable; void **cache_addr = (prop_op_type == IS_CONST) ? CACHE_ADDR(opline->extended_value & ~ZEND_RETURNS_FUNCTION) : NULL; + zend_refcounted *garbage = NULL; zend_fetch_property_address(variable_ptr, container, container_op_type, prop_ptr, prop_op_type, cache_addr, BP_VAR_W, 0, 0 OPLINE_CC EXECUTE_DATA_CC); @@ -3259,7 +3252,7 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { zend_property_info *prop_info = NULL; @@ -3271,9 +3264,9 @@ 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, variable_ptr, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } } } else if (Z_ISERROR_P(variable_ptr)) { @@ -3287,6 +3280,9 @@ static zend_always_inline void zend_assign_to_property_reference(zval *container if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } } static zend_never_inline void zend_assign_to_property_reference_this_const(zval *container, zval *prop_ptr, zval *value_ptr OPLINE_DC EXECUTE_DATA_DC) @@ -3581,15 +3577,11 @@ static zend_always_inline void i_zval_ptr_dtor_noref(zval *zval_ptr) { if (Z_REFCOUNTED_P(zval_ptr)) { zend_refcounted *ref = Z_COUNTED_P(zval_ptr); ZEND_ASSERT(Z_TYPE_P(zval_ptr) != IS_REFERENCE); - if (!GC_DELREF(ref)) { - rc_dtor_func(ref); - } else if (UNEXPECTED(GC_MAY_LEAK(ref))) { - gc_possible_root(ref); - } + GC_DTOR_NO_REF(ref); } } -ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, uint8_t value_type, bool strict) +ZEND_API zval* zend_assign_to_typed_ref_ex(zval *variable_ptr, zval *orig_value, uint8_t value_type, bool strict, zend_refcounted **garbage_ptr) { bool ret; zval value; @@ -3604,7 +3596,9 @@ ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, ui 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); + if (Z_REFCOUNTED_P(variable_ptr)) { + *garbage_ptr = Z_COUNTED_P(variable_ptr); + } ZVAL_COPY_VALUE(variable_ptr, &value); } else { zval_ptr_dtor_nogc(&value); @@ -3622,6 +3616,16 @@ ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, ui return variable_ptr; } +ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *orig_value, uint8_t value_type, bool strict) +{ + zend_refcounted *garbage = NULL; + zval *result = zend_assign_to_typed_ref_ex(variable_ptr, orig_value, value_type, strict, &garbage); + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + return result; +} + ZEND_API bool ZEND_FASTCALL zend_verify_prop_assignable_by_ref_ex(const zend_property_info *prop_info, zval *orig_val, bool strict, zend_verify_prop_assignable_by_ref_context context) { zval *val = orig_val; if (Z_ISREF_P(val) && ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(val))) { diff --git a/Zend/zend_execute.h b/Zend/zend_execute.h index 323b6269ee55e..9f2ff58b7632a 100644 --- a/Zend/zend_execute.h +++ b/Zend/zend_execute.h @@ -122,6 +122,7 @@ ZEND_API void ZEND_FASTCALL zend_ref_add_type_source(zend_property_info_source_l ZEND_API void ZEND_FASTCALL zend_ref_del_type_source(zend_property_info_source_list *source_list, const zend_property_info *prop); ZEND_API zval* zend_assign_to_typed_ref(zval *variable_ptr, zval *value, uint8_t value_type, bool strict); +ZEND_API zval* zend_assign_to_typed_ref_ex(zval *variable_ptr, zval *value, uint8_t value_type, bool strict, zend_refcounted **garbage_ptr); static zend_always_inline void zend_copy_to_variable(zval *variable_ptr, zval *value, uint8_t value_type) { @@ -168,15 +169,30 @@ static zend_always_inline zval* zend_assign_to_variable(zval *variable_ptr, zval } garbage = Z_COUNTED_P(variable_ptr); zend_copy_to_variable(variable_ptr, value, value_type); - if (GC_DELREF(garbage) == 0) { - rc_dtor_func(garbage); - } else { /* we need to split */ - /* optimized version of GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) */ - if (UNEXPECTED(GC_MAY_LEAK(garbage))) { - gc_possible_root(garbage); + GC_DTOR_NO_REF(garbage); + return variable_ptr; + } + } while (0); + + zend_copy_to_variable(variable_ptr, value, value_type); + return variable_ptr; +} + +static zend_always_inline zval* zend_assign_to_variable_ex(zval *variable_ptr, zval *value, zend_uchar value_type, bool strict, zend_refcounted **garbage_ptr) +{ + do { + if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) { + if (Z_ISREF_P(variable_ptr)) { + if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) { + return zend_assign_to_typed_ref_ex(variable_ptr, value, value_type, strict, garbage_ptr); + } + + variable_ptr = Z_REFVAL_P(variable_ptr); + if (EXPECTED(!Z_REFCOUNTED_P(variable_ptr))) { + break; } } - return variable_ptr; + *garbage_ptr = Z_COUNTED_P(variable_ptr); } } while (0); diff --git a/Zend/zend_gc.h b/Zend/zend_gc.h index 762f3180637e3..f4095e43bb69e 100644 --- a/Zend/zend_gc.h +++ b/Zend/zend_gc.h @@ -89,6 +89,14 @@ static zend_always_inline void gc_check_possible_root(zend_refcounted *ref) } } +static zend_always_inline void gc_check_possible_root_no_ref(zend_refcounted *ref) +{ + ZEND_ASSERT(GC_TYPE_INFO(ref) != GC_REFERENCE); + if (UNEXPECTED(GC_MAY_LEAK(ref))) { + gc_possible_root(ref); + } +} + /* These APIs can be used to simplify object get_gc implementations * over heterogeneous structures. See zend_generator_get_gc() for * a usage example. */ diff --git a/Zend/zend_object_handlers.c b/Zend/zend_object_handlers.c index 32e474b046419..1eb374821630f 100644 --- a/Zend/zend_object_handlers.c +++ b/Zend/zend_object_handlers.c @@ -839,9 +839,30 @@ ZEND_API zval *zend_std_write_property(zend_object *zobj, zend_string *name, zva value = &tmp; } -found: - variable_ptr = zend_assign_to_variable( - variable_ptr, value, IS_TMP_VAR, property_uses_strict_types()); +found:; + zend_refcounted *garbage = NULL; + + variable_ptr = zend_assign_to_variable_ex( + variable_ptr, value, IS_TMP_VAR, property_uses_strict_types(), &garbage); + + if (garbage) { + if (GC_DELREF(garbage) == 0) { + zend_execute_data *execute_data = EG(current_execute_data); + // Assign to result variable before calling the destructor as it may release the object + if (execute_data + && EX(func) + && ZEND_USER_CODE(EX(func)->common.type) + && EX(opline) + && EX(opline)->opcode == ZEND_ASSIGN_OBJ + && EX(opline)->result_type) { + ZVAL_COPY_DEREF(EX_VAR(EX(opline)->result.var), variable_ptr); + variable_ptr = NULL; + } + rc_dtor_func(garbage); + } else { + gc_check_possible_root_no_ref(garbage); + } + } goto exit; } if (Z_PROP_FLAG_P(variable_ptr) & IS_PROP_UNINIT) { diff --git a/Zend/zend_refcounted.h b/Zend/zend_refcounted.h index e4ffc99568530..b98e5a59604c7 100644 --- a/Zend/zend_refcounted.h +++ b/Zend/zend_refcounted.h @@ -56,6 +56,24 @@ #define GC_DELREF_EX(p, rc) zend_gc_delref_ex(&(p)->gc, rc) #define GC_TRY_ADDREF(p) zend_gc_try_addref(&(p)->gc) #define GC_TRY_DELREF(p) zend_gc_try_delref(&(p)->gc) +#define GC_DTOR(p) \ + do { \ + zend_refcounted_h *_p = &(p)->gc; \ + if (zend_gc_delref(_p) == 0) { \ + rc_dtor_func((zend_refcounted *)_p); \ + } else { \ + gc_check_possible_root((zend_refcounted *)_p); \ + } \ + } while (0) +#define GC_DTOR_NO_REF(p) \ + do { \ + zend_refcounted_h *_p = &(p)->gc; \ + if (zend_gc_delref(_p) == 0) { \ + rc_dtor_func((zend_refcounted *)_p); \ + } else { \ + gc_check_possible_root_no_ref((zend_refcounted *)_p); \ + } \ + } while (0) #define GC_NULL (IS_NULL | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) #define GC_STRING (IS_STRING | (GC_NOT_COLLECTABLE << GC_FLAGS_SHIFT)) diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 57d5cf887aca9..46ebbde41786f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2381,6 +2381,7 @@ ZEND_VM_HANDLER(24, ZEND_ASSIGN_OBJ, VAR|UNUSED|THIS|CV, CONST|TMPVAR|CV, CACHE_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = GET_OP1_OBJ_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); @@ -2410,11 +2411,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); ZEND_VM_C_GOTO(free_and_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()); + value = zend_assign_to_variable_ex(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -2493,11 +2494,14 @@ ZEND_VM_C_LABEL(fast_assign_obj): } ZEND_VM_C_LABEL(free_and_exit_assign_obj): - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } FREE_OP_DATA(); ZEND_VM_C_LABEL(exit_assign_obj): + if (garbage) { + GC_DTOR_NO_REF(garbage); + } FREE_OP2(); FREE_OP1(); /* assign_obj has two opcodes! */ @@ -2510,6 +2514,7 @@ ZEND_VM_HANDLER(25, ZEND_ASSIGN_STATIC_PROP, ANY, ANY, CACHE_SLOT, SPEC(OP_DATA= USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -2522,16 +2527,20 @@ 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, &garbage EXECUTE_DATA_CC); FREE_OP_DATA(); } else { - value = zend_assign_to_variable(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -2543,6 +2552,7 @@ ZEND_VM_HANDLER(23, ZEND_ASSIGN_DIM, VAR|CV, CONST|TMPVAR|UNUSED|NEXT|CV, SPEC(O zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); @@ -2598,11 +2608,14 @@ ZEND_VM_C_LABEL(try_assign_dim_array): ZEND_VM_C_GOTO(assign_dim_error); } value = GET_OP_DATA_ZVAL_PTR(BP_VAR_R); - value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -2695,9 +2708,18 @@ ZEND_VM_HANDLER(22, ZEND_ASSIGN, VAR|CV, CONST|TMP|VAR|CV, SPEC(RETVAL)) value = GET_OP2_ZVAL_PTR(BP_VAR_R); variable_ptr = GET_OP1_ZVAL_PTR_PTR_UNDEF(BP_VAR_W); - value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (!ZEND_VM_SPEC || UNEXPECTED(RETURN_VALUE_USED(opline))) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, OP2_TYPE, EX_USES_STRICT_TYPES()); } FREE_OP1(); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -2710,6 +2732,7 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = GET_OP2_ZVAL_PTR_PTR(BP_VAR_W); @@ -2725,15 +2748,19 @@ ZEND_VM_HANDLER(30, ZEND_ASSIGN_REF, VAR|CV, VAR|CV, SRC) 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP2(); FREE_OP1(); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -2781,6 +2808,7 @@ ZEND_VM_HANDLER(33, ZEND_ASSIGN_STATIC_PROP_REF, ANY, ANY, CACHE_SLOT|SRC) USE_OPLINE zval *prop, *value_ptr; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -2793,19 +2821,23 @@ 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); 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(prop, value_ptr, &garbage 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, prop, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), prop); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP_DATA(); ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -6423,11 +6455,7 @@ ZEND_VM_HANDLER(153, ZEND_UNSET_CV, CV, UNUSED) ZVAL_UNDEF(var); SAVE_OPLINE(); - if (!GC_DELREF(garbage)) { - rc_dtor_func(garbage); - } else { - gc_check_possible_root(garbage); - } + GC_DTOR(garbage); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { ZVAL_UNDEF(var); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 95e66b0cac3a7..de1c6eb379215 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -927,6 +927,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -939,16 +940,20 @@ 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, &garbage EXECUTE_DATA_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -958,6 +963,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -970,16 +976,20 @@ 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, &garbage EXECUTE_DATA_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()); + value = zend_assign_to_variable_ex(prop, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -989,6 +999,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1001,16 +1012,20 @@ 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, &garbage EXECUTE_DATA_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()); + value = zend_assign_to_variable_ex(prop, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -1020,6 +1035,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_SPEC_OP_DAT USE_OPLINE zval *prop, *value; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1032,16 +1048,20 @@ 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, &garbage EXECUTE_DATA_CC); } else { - value = zend_assign_to_variable(prop, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(prop, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + /* assign_static_prop has two opcodes! */ ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -1051,6 +1071,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_STATIC_PROP_REF_SPEC_HA USE_OPLINE zval *prop, *value_ptr; zend_property_info *prop_info; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); @@ -1063,19 +1084,23 @@ 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); 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(prop, value_ptr, &garbage 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, prop, value_ptr, &garbage EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(prop, value_ptr); + zend_assign_to_variable_reference(prop, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), prop); } + if (garbage) { + GC_DTOR(garbage); + } + FREE_OP((opline+1)->op1_type, (opline+1)->op1.var); ZEND_VM_NEXT_OPCODE_EX(1, 2); } @@ -23271,6 +23296,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23300,11 +23326,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23383,11 +23409,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23401,6 +23430,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23430,11 +23460,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23513,11 +23543,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23531,6 +23564,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23560,11 +23594,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23643,11 +23677,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23661,6 +23698,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23690,11 +23728,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -23773,11 +23811,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CONST_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -23792,6 +23833,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23847,11 +23889,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -23940,6 +23985,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -23995,11 +24041,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -24089,6 +24138,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -24144,11 +24194,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -24238,6 +24291,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -24293,11 +24347,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CONST_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -24389,9 +24446,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_RETVAL_U value = RT_CONSTANT(opline, opline->op2); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -24409,9 +24475,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CONST_RETVAL_U value = RT_CONSTANT(opline, opline->op2); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -26127,6 +26202,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26156,11 +26232,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26239,11 +26315,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26257,6 +26336,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26286,11 +26366,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26369,11 +26449,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26387,6 +26470,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26416,11 +26500,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26499,11 +26583,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26517,6 +26604,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26546,11 +26634,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -26629,11 +26717,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_TMPVAR_OP_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -26648,6 +26739,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26703,11 +26795,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26796,6 +26891,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -26851,11 +26947,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -26945,6 +27044,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -27000,11 +27100,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -27094,6 +27197,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -27149,11 +27253,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_TMPVAR_OP_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -27875,9 +27982,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_RETVAL_UNU value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27895,9 +28011,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_TMP_RETVAL_USE value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27959,9 +28084,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_RETVAL_UNU value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27979,9 +28113,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_VAR_RETVAL_USE value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -27994,6 +28137,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLE USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -28009,15 +28153,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_VAR_HANDLE 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -28179,6 +28327,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28234,11 +28383,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28327,6 +28479,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28382,11 +28535,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28476,6 +28632,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28531,11 +28688,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -28625,6 +28785,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -28680,11 +28841,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_UNUSED_OP_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -30330,6 +30494,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30359,11 +30524,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30442,11 +30607,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30460,6 +30628,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30489,11 +30658,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30572,11 +30741,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30590,6 +30762,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30619,11 +30792,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30702,11 +30875,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30720,6 +30896,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30749,11 +30926,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -30832,11 +31009,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_VAR_CV_OP_DATA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* assign_obj has two opcodes! */ @@ -30851,6 +31031,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -30906,11 +31087,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -30999,6 +31183,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -31054,11 +31239,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -31148,6 +31336,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -31203,11 +31392,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -31297,6 +31489,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); @@ -31352,11 +31545,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_VAR_CV_OP_DATA goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -31448,9 +31644,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_RETVAL_UNUS value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -31468,9 +31673,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_VAR_CV_RETVAL_USED value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = _get_zval_ptr_ptr_var(opline->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -31483,6 +31697,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC); @@ -31498,15 +31713,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_VAR_CV_HANDLER 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op1.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } @@ -32908,6 +33127,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -32937,11 +33157,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33020,11 +33240,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -33038,6 +33261,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -33067,11 +33291,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33150,11 +33374,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -33168,6 +33395,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -33197,11 +33425,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33280,11 +33508,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -33298,6 +33529,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -33327,11 +33559,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -33410,11 +33642,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CONST_O } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -34926,6 +35161,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -34955,11 +35191,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -35038,11 +35274,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -35056,6 +35295,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -35085,11 +35325,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -35168,11 +35408,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -35186,6 +35429,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -35215,11 +35459,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -35298,11 +35542,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -35316,6 +35563,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -35345,11 +35593,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -35428,11 +35676,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_TMPVAR_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -37400,6 +37651,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37429,11 +37681,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37512,11 +37764,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37530,6 +37785,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37559,11 +37815,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37642,11 +37898,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37660,6 +37919,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37689,11 +37949,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37772,11 +38032,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -37790,6 +38053,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = &EX(This); @@ -37819,11 +38083,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -37902,11 +38166,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_UNUSED_CV_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41577,6 +41844,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41606,11 +41874,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41689,11 +41957,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41707,6 +41978,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41736,11 +42008,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41819,11 +42091,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41837,6 +42112,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41866,11 +42142,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -41949,11 +42225,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -41967,6 +42246,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -41996,11 +42276,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -42079,11 +42359,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CONST_OP_DA } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -42098,6 +42381,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -42153,11 +42437,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -42246,6 +42533,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -42301,11 +42589,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -42395,6 +42686,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -42450,11 +42742,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -42544,6 +42839,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -42599,11 +42895,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CONST_OP_DA goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -42695,9 +42994,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_UN value = RT_CONSTANT(opline, opline->op2); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -42715,9 +43023,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CONST_RETVAL_US value = RT_CONSTANT(opline, opline->op2); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -45366,6 +45683,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45395,11 +45713,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45478,11 +45796,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45496,6 +45817,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45525,11 +45847,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45608,11 +45930,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45626,6 +45951,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45655,11 +45981,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45738,11 +46064,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45756,6 +46085,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -45785,11 +46115,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -45868,11 +46198,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_TMPVAR_OP_D } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); /* assign_obj has two opcodes! */ @@ -45887,6 +46220,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -45942,11 +46276,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -46035,6 +46372,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -46090,11 +46428,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -46184,6 +46525,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -46239,11 +46581,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -46333,6 +46678,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -46388,11 +46734,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_TMPVAR_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -47407,9 +47756,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_RETVAL_UNUS value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -47427,9 +47785,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_TMP_RETVAL_USED value = _get_zval_ptr_tmp(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -47477,9 +47844,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_UNUS value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -47497,9 +47873,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_VAR_RETVAL_USED value = _get_zval_ptr_var(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -47512,6 +47897,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_ptr_var(opline->op2.var EXECUTE_DATA_CC); @@ -47527,15 +47913,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_VAR_HANDLER 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + zval_ptr_dtor_nogc(EX_VAR(opline->op2.var)); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); @@ -47870,6 +48260,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -47925,11 +48316,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -48018,6 +48412,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -48073,11 +48468,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -48167,6 +48565,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -48222,11 +48621,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -48316,6 +48718,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -48371,11 +48774,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_UNUSED_OP_D goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -48858,11 +49264,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_UNSET_CV_SPEC_CV_UNUSED_HANDLE ZVAL_UNDEF(var); SAVE_OPLINE(); - if (!GC_DELREF(garbage)) { - rc_dtor_func(garbage); - } else { - gc_check_possible_root(garbage); - } + GC_DTOR(garbage); ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } else { ZVAL_UNDEF(var); @@ -50694,6 +51096,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50723,11 +51126,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50806,11 +51209,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50824,6 +51230,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50853,11 +51260,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -50936,11 +51343,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -50954,6 +51364,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -50983,11 +51394,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -51066,11 +51477,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } zval_ptr_dtor_nogc(EX_VAR((opline+1)->op1.var)); exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -51084,6 +51498,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ zval *object, *value, tmp; zend_object *zobj; zend_string *name, *tmp_name; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); object = EX_VAR(opline->op1.var); @@ -51113,11 +51528,11 @@ 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); + value = zend_assign_to_typed_prop(prop_info, property_val, value, &garbage EXECUTE_DATA_CC); goto free_and_exit_assign_obj; } else { fast_assign_obj: - value = zend_assign_to_variable(property_val, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(property_val, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } @@ -51196,11 +51611,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_OBJ_SPEC_CV_CV_OP_DATA_ } free_and_exit_assign_obj: - if (UNEXPECTED(RETURN_VALUE_USED(opline))) { + if (UNEXPECTED(RETURN_VALUE_USED(opline)) && value) { ZVAL_COPY_DEREF(EX_VAR(opline->result.var), value); } exit_assign_obj: + if (garbage) { + GC_DTOR_NO_REF(garbage); + } /* assign_obj has two opcodes! */ @@ -51215,6 +51633,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51270,11 +51689,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = RT_CONSTANT((opline+1), (opline+1)->op1); - value = zend_assign_to_variable(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CONST, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51363,6 +51785,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51418,11 +51841,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_tmp((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_TMP_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51512,6 +51938,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51567,11 +51994,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_var((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_VAR, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51661,6 +52091,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ zval *value; zval *variable_ptr; zval *dim; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); orig_object_ptr = object_ptr = EX_VAR(opline->op1.var); @@ -51716,11 +52147,14 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_DIM_SPEC_CV_CV_OP_DATA_ goto assign_dim_error; } value = _get_zval_ptr_cv_BP_VAR_R((opline+1)->op1.var EXECUTE_DATA_CC); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), value); } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } } else { if (EXPECTED(Z_ISREF_P(object_ptr))) { object_ptr = Z_REFVAL_P(object_ptr); @@ -51812,9 +52246,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_RETVAL_UNUSE value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(0)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(0)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(0)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -51832,9 +52275,18 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_SPEC_CV_CV_RETVAL_USED_ value = _get_zval_ptr_cv_BP_VAR_R(opline->op2.var EXECUTE_DATA_CC); variable_ptr = EX_VAR(opline->op1.var); - value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (UNEXPECTED(1)) { - ZVAL_COPY(EX_VAR(opline->result.var), value); + if (0 || UNEXPECTED(1)) { + zend_refcounted *garbage = NULL; + + value = zend_assign_to_variable_ex(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES(), &garbage); + if (UNEXPECTED(1)) { + ZVAL_COPY(EX_VAR(opline->result.var), value); + } + if (garbage) { + GC_DTOR_NO_REF(garbage); + } + } else { + value = zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); } /* zend_assign_to_variable() always takes care of op2, never free it! */ @@ -51847,6 +52299,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER( USE_OPLINE zval *variable_ptr; zval *value_ptr; + zend_refcounted *garbage = NULL; SAVE_OPLINE(); value_ptr = _get_zval_ptr_cv_BP_VAR_W(opline->op2.var EXECUTE_DATA_CC); @@ -51862,15 +52315,19 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_ASSIGN_REF_SPEC_CV_CV_HANDLER( 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, value_ptr, &garbage OPLINE_CC EXECUTE_DATA_CC); } else { - zend_assign_to_variable_reference(variable_ptr, value_ptr); + zend_assign_to_variable_reference(variable_ptr, value_ptr, &garbage); } if (UNEXPECTED(RETURN_VALUE_USED(opline))) { ZVAL_COPY(EX_VAR(opline->result.var), variable_ptr); } + if (garbage) { + GC_DTOR(garbage); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/ext/opcache/jit/zend_jit_helpers.c b/ext/opcache/jit/zend_jit_helpers.c index 7c889a2ade8df..4da73d770f1c2 100644 --- a/ext/opcache/jit/zend_jit_helpers.c +++ b/ext/opcache/jit/zend_jit_helpers.c @@ -2496,7 +2496,7 @@ static void ZEND_FASTCALL zend_jit_assign_obj_helper(zend_object *zobj, zend_str ZVAL_DEREF(value); value = zobj->handlers->write_property(zobj, name, value, cache_slot); - if (result) { + if (result && value) { ZVAL_COPY_DEREF(result, value); } }