From: Nikita Popov Date: Fri, 8 May 2015 13:05:59 +0000 (+0200) Subject: Fix static closure error in call_user_func opcode X-Git-Tag: PRE_PHP7_NSAPI_REMOVAL~59 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=8f9f21e8d24c1b48dc271330e38f2931086c0c94;p=php Fix static closure error in call_user_func opcode I'm assuming this is the only error that is_callable() can generate with retval=1. This problem manifested after making closures in static methods not implicitly static, but would also occur when binding any non-static closure to a scope without a $this. --- diff --git a/Zend/tests/call_user_func_closure_from_static_method.phpt b/Zend/tests/call_user_func_closure_from_static_method.phpt new file mode 100644 index 0000000000..b427b85527 --- /dev/null +++ b/Zend/tests/call_user_func_closure_from_static_method.phpt @@ -0,0 +1,22 @@ +--TEST-- +call_user_func() on non-static closure without $this inside a static method +--FILE-- + +--EXPECT-- +string(4) "okay" diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 95022ac2cc..7d324fe08f 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -3314,9 +3314,6 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV) SAVE_OPLINE(); function_name = GET_OP2_ZVAL_PTR(BP_VAR_R); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { - if (error) { - efree(error); - } func = fcc.function_handler; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ @@ -3332,20 +3329,13 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV) if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ - } else if (func->common.scope && - !(func->common.fn_flags & ZEND_ACC_STATIC)) { - if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, + } + if (error) { + efree(error); + /* This is the only soft error is_callable() can generate */ + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically", func->common.scope->name->val, func->common.function_name->val); - } else { - zend_error( - E_EXCEPTION | E_ERROR, - "Non-static method %s::%s() cannot be called statically", - func->common.scope->name->val, func->common.function_name->val); - FREE_OP2(); - HANDLE_EXCEPTION(); - } } } else { zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error); diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index f4bdf0d882..7abf0f9854 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -5649,9 +5649,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS SAVE_OPLINE(); function_name = EX_CONSTANT(opline->op2); if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) { - if (error) { - efree(error); - } func = fcc.function_handler; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ @@ -5667,20 +5664,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ - } else if (func->common.scope && - !(func->common.fn_flags & ZEND_ACC_STATIC)) { - if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, + } + if (error) { + efree(error); + /* This is the only soft error is_callable() can generate */ + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically", func->common.scope->name->val, func->common.function_name->val); - } else { - zend_error( - E_EXCEPTION | E_ERROR, - "Non-static method %s::%s() cannot be called statically", - func->common.scope->name->val, func->common.function_name->val); - - HANDLE_EXCEPTION(); - } } } else { zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error); @@ -9296,9 +9286,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H SAVE_OPLINE(); 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)) { - if (error) { - efree(error); - } func = fcc.function_handler; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ @@ -9314,20 +9301,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CV_H if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ - } else if (func->common.scope && - !(func->common.fn_flags & ZEND_ACC_STATIC)) { - if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, + } + if (error) { + efree(error); + /* This is the only soft error is_callable() can generate */ + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically", func->common.scope->name->val, func->common.function_name->val); - } else { - zend_error( - E_EXCEPTION | E_ERROR, - "Non-static method %s::%s() cannot be called statically", - func->common.scope->name->val, func->common.function_name->val); - - HANDLE_EXCEPTION(); - } } } else { zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error); @@ -11032,9 +11012,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV SAVE_OPLINE(); 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)) { - if (error) { - efree(error); - } func = fcc.function_handler; if (func->common.fn_flags & ZEND_ACC_CLOSURE) { /* Delay closure destruction until its invocation */ @@ -11050,20 +11027,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV if (object) { call_info |= ZEND_CALL_RELEASE_THIS; GC_REFCOUNT(object)++; /* For $this pointer */ - } else if (func->common.scope && - !(func->common.fn_flags & ZEND_ACC_STATIC)) { - if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) { - zend_error(E_DEPRECATED, + } + if (error) { + efree(error); + /* This is the only soft error is_callable() can generate */ + zend_error(E_DEPRECATED, "Non-static method %s::%s() should not be called statically", func->common.scope->name->val, func->common.function_name->val); - } else { - zend_error( - E_EXCEPTION | E_ERROR, - "Non-static method %s::%s() cannot be called statically", - func->common.scope->name->val, func->common.function_name->val); - zval_ptr_dtor_nogc(free_op2); - HANDLE_EXCEPTION(); - } } } else { zend_internal_type_error(EX_USES_STRICT_TYPES(), "%s() expects parameter 1 to be a valid callback, %s", Z_STRVAL_P(EX_CONSTANT(opline->op1)), error);