Skip to content

Commit 8f9f21e

Browse files
committed
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.
1 parent 9d4465e commit 8f9f21e

File tree

3 files changed

+42
-60
lines changed

3 files changed

+42
-60
lines changed
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--TEST--
2+
call_user_func() on non-static closure without $this inside a static method
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public static function exec(callable $c) {
8+
return call_user_func($c);
9+
}
10+
11+
public static function doSomething() {
12+
return self::exec(function(){
13+
return "okay";
14+
});
15+
}
16+
}
17+
18+
var_dump(A::doSomething());
19+
20+
?>
21+
--EXPECT--
22+
string(4) "okay"

Zend/zend_vm_def.h

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3314,9 +3314,6 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
33143314
SAVE_OPLINE();
33153315
function_name = GET_OP2_ZVAL_PTR(BP_VAR_R);
33163316
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
3317-
if (error) {
3318-
efree(error);
3319-
}
33203317
func = fcc.function_handler;
33213318
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
33223319
/* Delay closure destruction until its invocation */
@@ -3332,20 +3329,13 @@ ZEND_VM_HANDLER(118, ZEND_INIT_USER_CALL, CONST, CONST|TMPVAR|CV)
33323329
if (object) {
33333330
call_info |= ZEND_CALL_RELEASE_THIS;
33343331
GC_REFCOUNT(object)++; /* For $this pointer */
3335-
} else if (func->common.scope &&
3336-
!(func->common.fn_flags & ZEND_ACC_STATIC)) {
3337-
if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
3338-
zend_error(E_DEPRECATED,
3332+
}
3333+
if (error) {
3334+
efree(error);
3335+
/* This is the only soft error is_callable() can generate */
3336+
zend_error(E_DEPRECATED,
33393337
"Non-static method %s::%s() should not be called statically",
33403338
func->common.scope->name->val, func->common.function_name->val);
3341-
} else {
3342-
zend_error(
3343-
E_EXCEPTION | E_ERROR,
3344-
"Non-static method %s::%s() cannot be called statically",
3345-
func->common.scope->name->val, func->common.function_name->val);
3346-
FREE_OP2();
3347-
HANDLE_EXCEPTION();
3348-
}
33493339
}
33503340
} else {
33513341
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);

Zend/zend_vm_execute.h

Lines changed: 15 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -5649,9 +5649,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
56495649
SAVE_OPLINE();
56505650
function_name = EX_CONSTANT(opline->op2);
56515651
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
5652-
if (error) {
5653-
efree(error);
5654-
}
56555652
func = fcc.function_handler;
56565653
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
56575654
/* Delay closure destruction until its invocation */
@@ -5667,20 +5664,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_CONS
56675664
if (object) {
56685665
call_info |= ZEND_CALL_RELEASE_THIS;
56695666
GC_REFCOUNT(object)++; /* For $this pointer */
5670-
} else if (func->common.scope &&
5671-
!(func->common.fn_flags & ZEND_ACC_STATIC)) {
5672-
if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
5673-
zend_error(E_DEPRECATED,
5667+
}
5668+
if (error) {
5669+
efree(error);
5670+
/* This is the only soft error is_callable() can generate */
5671+
zend_error(E_DEPRECATED,
56745672
"Non-static method %s::%s() should not be called statically",
56755673
func->common.scope->name->val, func->common.function_name->val);
5676-
} else {
5677-
zend_error(
5678-
E_EXCEPTION | E_ERROR,
5679-
"Non-static method %s::%s() cannot be called statically",
5680-
func->common.scope->name->val, func->common.function_name->val);
5681-
5682-
HANDLE_EXCEPTION();
5683-
}
56845674
}
56855675
} else {
56865676
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
92969286
SAVE_OPLINE();
92979287
function_name = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op2.var);
92989288
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
9299-
if (error) {
9300-
efree(error);
9301-
}
93029289
func = fcc.function_handler;
93039290
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
93049291
/* 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
93149301
if (object) {
93159302
call_info |= ZEND_CALL_RELEASE_THIS;
93169303
GC_REFCOUNT(object)++; /* For $this pointer */
9317-
} else if (func->common.scope &&
9318-
!(func->common.fn_flags & ZEND_ACC_STATIC)) {
9319-
if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
9320-
zend_error(E_DEPRECATED,
9304+
}
9305+
if (error) {
9306+
efree(error);
9307+
/* This is the only soft error is_callable() can generate */
9308+
zend_error(E_DEPRECATED,
93219309
"Non-static method %s::%s() should not be called statically",
93229310
func->common.scope->name->val, func->common.function_name->val);
9323-
} else {
9324-
zend_error(
9325-
E_EXCEPTION | E_ERROR,
9326-
"Non-static method %s::%s() cannot be called statically",
9327-
func->common.scope->name->val, func->common.function_name->val);
9328-
9329-
HANDLE_EXCEPTION();
9330-
}
93319311
}
93329312
} else {
93339313
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
1103211012
SAVE_OPLINE();
1103311013
function_name = _get_zval_ptr_var(opline->op2.var, execute_data, &free_op2);
1103411014
if (zend_is_callable_ex(function_name, NULL, 0, NULL, &fcc, &error)) {
11035-
if (error) {
11036-
efree(error);
11037-
}
1103811015
func = fcc.function_handler;
1103911016
if (func->common.fn_flags & ZEND_ACC_CLOSURE) {
1104011017
/* Delay closure destruction until its invocation */
@@ -11050,20 +11027,13 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_INIT_USER_CALL_SPEC_CONST_TMPV
1105011027
if (object) {
1105111028
call_info |= ZEND_CALL_RELEASE_THIS;
1105211029
GC_REFCOUNT(object)++; /* For $this pointer */
11053-
} else if (func->common.scope &&
11054-
!(func->common.fn_flags & ZEND_ACC_STATIC)) {
11055-
if (func->common.fn_flags & ZEND_ACC_ALLOW_STATIC) {
11056-
zend_error(E_DEPRECATED,
11030+
}
11031+
if (error) {
11032+
efree(error);
11033+
/* This is the only soft error is_callable() can generate */
11034+
zend_error(E_DEPRECATED,
1105711035
"Non-static method %s::%s() should not be called statically",
1105811036
func->common.scope->name->val, func->common.function_name->val);
11059-
} else {
11060-
zend_error(
11061-
E_EXCEPTION | E_ERROR,
11062-
"Non-static method %s::%s() cannot be called statically",
11063-
func->common.scope->name->val, func->common.function_name->val);
11064-
zval_ptr_dtor_nogc(free_op2);
11065-
HANDLE_EXCEPTION();
11066-
}
1106711037
}
1106811038
} else {
1106911039
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);

0 commit comments

Comments
 (0)