From: Dmitry Stogov Date: Thu, 31 Mar 2016 15:58:13 +0000 (+0300) Subject: Flags ZEND_CALL_RELEASE_THIS and ZEND_CALL_CLOSURE should never be set together. X-Git-Tag: php-7.1.0alpha1~392^2 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=86a1aeed227c1c73069cfae350197e992e3eb841;p=php Flags ZEND_CALL_RELEASE_THIS and ZEND_CALL_CLOSURE should never be set together. Closures keep responsibility for releasing $this theirselves. --- diff --git a/Zend/zend_execute.c b/Zend/zend_execute.c index 5abc2ad75a..9aa2d7762f 100644 --- a/Zend/zend_execute.c +++ b/Zend/zend_execute.c @@ -2311,9 +2311,6 @@ ZEND_API zend_execute_data *zend_create_generator_execute_data(zend_execute_data EG(vm_stack_end) = EG(vm_stack)->end; call_info = ZEND_CALL_TOP_FUNCTION | ZEND_CALL_ALLOCATED | (ZEND_CALL_INFO(call) & (ZEND_CALL_CLOSURE|ZEND_CALL_RELEASE_THIS)); - if (Z_OBJ(call->This)) { - call_info |= ZEND_CALL_RELEASE_THIS; - } execute_data = zend_vm_stack_push_call_frame( call_info, (zend_function*)op_array, diff --git a/Zend/zend_generators.c b/Zend/zend_generators.c index 5a3e84ccd1..4e65c92313 100644 --- a/Zend/zend_generators.c +++ b/Zend/zend_generators.c @@ -69,7 +69,7 @@ ZEND_API void zend_generator_close(zend_generator *generator, zend_bool finished /* always free the CV's, in the symtable are only not-free'd IS_INDIRECT's */ zend_free_compiled_variables(execute_data); - if (Z_OBJ(execute_data->This)) { + if (EX_CALL_INFO() & ZEND_CALL_RELEASE_THIS) { OBJ_RELEASE(Z_OBJ(execute_data->This)); } @@ -334,7 +334,7 @@ ZEND_API void zend_generator_create_zval(zend_execute_data *call, zend_op_array object_init_ex(return_value, zend_ce_generator); - if (Z_OBJ(call->This)) { + if (ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS) { Z_ADDREF(call->This); } diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index b4303954ce..ec147ece3b 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -2527,9 +2527,6 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) zend_vm_stack_free_extra_args_ex(call_info, execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype); - } if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { object = Z_OBJ(old_execute_data->This); #if 0 @@ -2543,6 +2540,8 @@ ZEND_VM_HELPER(zend_leave_helper, ANY, ANY) } } OBJ_RELEASE(object); + } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { + OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype); } EG(scope) = EX(func)->op_array.scope; @@ -3583,6 +3582,8 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { func = fcc.function_handler; + called_scope = fcc.called_scope; + object = fcc.object; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ if (OP2_TYPE & (IS_VAR|IS_CV)) { @@ -3591,10 +3592,7 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV, NUM) ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); GC_REFCOUNT((zend_object*)func->common.prototype)++; call_info |= ZEND_CALL_CLOSURE; - } - called_scope = fcc.called_scope; - object = fcc.object; - if (object) { + } else if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index 69df98c660..7c3efd4938 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -484,9 +484,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ zend_vm_stack_free_extra_args_ex(call_info, execute_data); old_execute_data = execute_data; execute_data = EG(current_execute_data) = EX(prev_execute_data); - if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { - OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype); - } if (UNEXPECTED(call_info & ZEND_CALL_RELEASE_THIS)) { object = Z_OBJ(old_execute_data->This); #if 0 @@ -500,6 +497,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_leave_helper_SPEC(ZEND_OPCODE_ } } OBJ_RELEASE(object); + } else if (UNEXPECTED(call_info & ZEND_CALL_CLOSURE)) { + OBJ_RELEASE((zend_object*)old_execute_data->func->op_array.prototype); } EG(scope) = EX(func)->op_array.scope; @@ -6198,6 +6197,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS function_name = EX_CONSTANT(opline->op2); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { func = fcc.function_handler; + called_scope = fcc.called_scope; + object = fcc.object; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ if (IS_CONST & (IS_VAR|IS_CV)) { @@ -6206,10 +6207,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); GC_REFCOUNT((zend_object*)func->common.prototype)++; call_info |= ZEND_CALL_CLOSURE; - } - called_scope = fcc.called_scope; - object = fcc.object; - if (object) { + } else if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ } @@ -10006,6 +10004,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { func = fcc.function_handler; + called_scope = fcc.called_scope; + object = fcc.object; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ if (IS_CV & (IS_VAR|IS_CV)) { @@ -10014,10 +10014,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); GC_REFCOUNT((zend_object*)func->common.prototype)++; call_info |= ZEND_CALL_CLOSURE; - } - called_scope = fcc.called_scope; - object = fcc.object; - if (object) { + } else if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ } @@ -11913,6 +11910,8 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { func = fcc.function_handler; + called_scope = fcc.called_scope; + object = fcc.object; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ if ((IS_TMP_VAR|IS_VAR) & (IS_VAR|IS_CV)) { @@ -11921,10 +11920,7 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV ZEND_ASSERT(GC_TYPE((zend_object*)func->common.prototype) == IS_OBJECT); GC_REFCOUNT((zend_object*)func->common.prototype)++; call_info |= ZEND_CALL_CLOSURE; - } - called_scope = fcc.called_scope; - object = fcc.object; - if (object) { + } else if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ }