mirror of
https://github.com/php/php-src.git
synced 2024-11-23 09:54:15 +08:00
call_user_func(_array): Don't abort on reference warning
Change zend_call_function() to not abort the call if a non-reference is passed to a reference argument. The usual warning will still be thrown, but the call will proceed as usual.
This commit is contained in:
parent
26d74a0420
commit
906456c410
54
Zend/tests/call_user_func_008.phpt
Normal file
54
Zend/tests/call_user_func_008.phpt
Normal file
@ -0,0 +1,54 @@
|
||||
--TEST--
|
||||
call_user_func() behavior with references
|
||||
--FILE--
|
||||
<?php
|
||||
|
||||
function test(&$ref1, &$ref2) {
|
||||
$ref1 += 42;
|
||||
$ref2 -= 42;
|
||||
return true;
|
||||
}
|
||||
|
||||
$i = $j = 0;
|
||||
var_dump(call_user_func('test', $i, $j));
|
||||
var_dump($i, $j);
|
||||
|
||||
var_dump(call_user_func_array('test', [$i, $j]));
|
||||
var_dump($i, $j);
|
||||
|
||||
$x =& $i; $y =& $j;
|
||||
var_dump(call_user_func('test', $i, $j));
|
||||
var_dump($i, $j);
|
||||
|
||||
var_dump(call_user_func_array('test', [$i, $j]));
|
||||
var_dump($i, $j);
|
||||
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
|
||||
|
||||
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
||||
|
||||
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
|
||||
|
||||
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
||||
|
||||
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
|
||||
|
||||
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
||||
|
||||
Warning: Parameter 1 to test() expected to be a reference, value given in %s on line %d
|
||||
|
||||
Warning: Parameter 2 to test() expected to be a reference, value given in %s on line %d
|
||||
bool(true)
|
||||
int(0)
|
||||
int(0)
|
@ -788,41 +788,29 @@ int zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache) /
|
||||
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
|
||||
if (UNEXPECTED(!Z_ISREF_P(arg))) {
|
||||
if (fci->no_separation &&
|
||||
!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
|
||||
if (i) {
|
||||
/* hack to clean up the stack */
|
||||
ZEND_CALL_NUM_ARGS(call) = i;
|
||||
zend_vm_stack_free_args(call);
|
||||
}
|
||||
zend_vm_stack_free_call_frame(call);
|
||||
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
i+1,
|
||||
if (!fci->no_separation) {
|
||||
/* Separation is enabled -- create a ref */
|
||||
ZVAL_NEW_REF(arg, arg);
|
||||
} else if (!ARG_MAY_BE_SENT_BY_REF(func, i + 1)) {
|
||||
/* By-value send is not allowed -- emit a warning,
|
||||
* but still perform the call with a by-value send. */
|
||||
zend_error(E_WARNING,
|
||||
"Parameter %d to %s%s%s() expected to be a reference, value given", i+1,
|
||||
func->common.scope ? ZSTR_VAL(func->common.scope->name) : "",
|
||||
func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(func->common.function_name));
|
||||
if (EG(current_execute_data) == &dummy_execute_data) {
|
||||
EG(current_execute_data) = dummy_execute_data.prev_execute_data;
|
||||
}
|
||||
return FAILURE;
|
||||
}
|
||||
|
||||
ZVAL_NEW_REF(arg, arg);
|
||||
}
|
||||
Z_ADDREF_P(arg);
|
||||
} else {
|
||||
if (Z_ISREF_P(arg) &&
|
||||
!(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
/* don't separate references for __call */
|
||||
arg = Z_REFVAL_P(arg);
|
||||
}
|
||||
if (Z_OPT_REFCOUNTED_P(arg)) {
|
||||
Z_ADDREF_P(arg);
|
||||
}
|
||||
}
|
||||
|
||||
param = ZEND_CALL_ARG(call, i+1);
|
||||
ZVAL_COPY_VALUE(param, arg);
|
||||
ZVAL_COPY(param, arg);
|
||||
}
|
||||
|
||||
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
|
||||
|
@ -4626,23 +4626,15 @@ ZEND_VM_C_LABEL(send_array):
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
if (UNEXPECTED(!Z_ISREF_P(arg))) {
|
||||
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
/* By-value send is not allowed -- emit a warning,
|
||||
* but still perform the call. */
|
||||
zend_error(E_WARNING,
|
||||
"Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
arg_num,
|
||||
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
|
||||
EX(call)->func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(EX(call)->func->common.function_name));
|
||||
|
||||
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
|
||||
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
|
||||
}
|
||||
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
|
||||
OBJ_RELEASE(Z_OBJ(EX(call)->This));
|
||||
}
|
||||
EX(call)->func = (zend_function*)&zend_pass_function;
|
||||
Z_OBJ(EX(call)->This) = NULL;
|
||||
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -4673,25 +4665,12 @@ ZEND_VM_HANDLER(120, ZEND_SEND_USER, VAR|CV, NUM)
|
||||
param = ZEND_CALL_VAR(EX(call), opline->result.var);
|
||||
|
||||
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
|
||||
ZVAL_DEREF(arg);
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
opline->op2.num,
|
||||
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
|
||||
EX(call)->func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(EX(call)->func->common.function_name));
|
||||
|
||||
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
|
||||
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
|
||||
}
|
||||
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
|
||||
OBJ_RELEASE(Z_OBJ(EX(call)->This));
|
||||
}
|
||||
ZVAL_UNDEF(param);
|
||||
EX(call)->func = (zend_function*)&zend_pass_function;
|
||||
Z_OBJ(EX(call)->This) = NULL;
|
||||
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
|
||||
|
||||
FREE_OP1();
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
} else {
|
||||
if (Z_ISREF_P(arg) &&
|
||||
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
|
@ -1423,23 +1423,15 @@ send_array:
|
||||
if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
if (UNEXPECTED(!Z_ISREF_P(arg))) {
|
||||
if (!ARG_MAY_BE_SENT_BY_REF(EX(call)->func, arg_num)) {
|
||||
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
/* By-value send is not allowed -- emit a warning,
|
||||
* but still perform the call. */
|
||||
zend_error(E_WARNING,
|
||||
"Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
arg_num,
|
||||
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
|
||||
EX(call)->func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(EX(call)->func->common.function_name));
|
||||
|
||||
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
|
||||
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
|
||||
}
|
||||
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
|
||||
OBJ_RELEASE(Z_OBJ(EX(call)->This));
|
||||
}
|
||||
EX(call)->func = (zend_function*)&zend_pass_function;
|
||||
Z_OBJ(EX(call)->This) = NULL;
|
||||
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
|
||||
break;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -15904,25 +15896,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEN
|
||||
param = ZEND_CALL_VAR(EX(call), opline->result.var);
|
||||
|
||||
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
|
||||
ZVAL_DEREF(arg);
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
opline->op2.num,
|
||||
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
|
||||
EX(call)->func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(EX(call)->func->common.function_name));
|
||||
|
||||
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
|
||||
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
|
||||
}
|
||||
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
|
||||
OBJ_RELEASE(Z_OBJ(EX(call)->This));
|
||||
}
|
||||
ZVAL_UNDEF(param);
|
||||
EX(call)->func = (zend_function*)&zend_pass_function;
|
||||
Z_OBJ(EX(call)->This) = NULL;
|
||||
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
|
||||
|
||||
zval_ptr_dtor_nogc(free_op1);
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
} else {
|
||||
if (Z_ISREF_P(arg) &&
|
||||
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
@ -34925,24 +34904,12 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND
|
||||
param = ZEND_CALL_VAR(EX(call), opline->result.var);
|
||||
|
||||
if (UNEXPECTED(ARG_MUST_BE_SENT_BY_REF(EX(call)->func, opline->op2.num))) {
|
||||
ZVAL_DEREF(arg);
|
||||
zend_error(E_WARNING, "Parameter %d to %s%s%s() expected to be a reference, value given",
|
||||
opline->op2.num,
|
||||
EX(call)->func->common.scope ? ZSTR_VAL(EX(call)->func->common.scope->name) : "",
|
||||
EX(call)->func->common.scope ? "::" : "",
|
||||
ZSTR_VAL(EX(call)->func->common.function_name));
|
||||
|
||||
if (ZEND_CALL_INFO(EX(call)) & ZEND_CALL_CLOSURE) {
|
||||
OBJ_RELEASE((zend_object*)EX(call)->func->common.prototype);
|
||||
}
|
||||
if (Z_TYPE(EX(call)->This) == IS_OBJECT) {
|
||||
OBJ_RELEASE(Z_OBJ(EX(call)->This));
|
||||
}
|
||||
ZVAL_UNDEF(param);
|
||||
EX(call)->func = (zend_function*)&zend_pass_function;
|
||||
Z_OBJ(EX(call)->This) = NULL;
|
||||
ZEND_SET_CALL_INFO(EX(call), 0, ZEND_CALL_INFO(EX(call)) & ~ZEND_CALL_RELEASE_THIS);
|
||||
|
||||
ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION();
|
||||
} else {
|
||||
if (Z_ISREF_P(arg) &&
|
||||
!(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) {
|
||||
|
Binary file not shown.
@ -6,7 +6,7 @@ echo "hi";
|
||||
';
|
||||
$a->setStub('<?php
|
||||
try {
|
||||
Phar::webPhar("test.phar", "/index.php", null, array(), "sort");
|
||||
Phar::webPhar("test.phar", "/index.php", null, array(), function() { throw new Exception; });
|
||||
} catch (Exception $e) {
|
||||
die($e->getMessage() . "\n");
|
||||
}
|
||||
|
@ -13,4 +13,4 @@ Content-type: text/html; charset=UTF-8
|
||||
--FILE_EXTERNAL--
|
||||
files/frontcontroller17.phar
|
||||
--EXPECTF--
|
||||
%ahar error: failed to call rewrite callback
|
||||
%ahar error: rewrite callback must return a string or false
|
||||
|
Binary file not shown.
@ -6,7 +6,7 @@ echo "hi";
|
||||
';
|
||||
$a->setStub('<?php
|
||||
try {
|
||||
Phar::webPhar("test.phar", "/index.php", null, array(), "sort");
|
||||
Phar::webPhar("test.phar", "/index.php", null, array(), function() { throw new Exception; });
|
||||
} catch (Exception $e) {
|
||||
die($e->getMessage() . "\n");
|
||||
}
|
||||
|
@ -12,4 +12,4 @@ Content-type: text/html; charset=UTF-8
|
||||
--FILE_EXTERNAL--
|
||||
files/frontcontroller17.phar
|
||||
--EXPECTF--
|
||||
%ahar error: failed to call rewrite callback
|
||||
%ahar error: rewrite callback must return a string or false
|
||||
|
@ -27,12 +27,8 @@ echo "Done\n";
|
||||
string(9) "x.changed"
|
||||
|
||||
Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 15
|
||||
|
||||
Warning: ReflectionClass::newInstance(): Invocation of C's constructor failed in %sbug42976.php on line 15
|
||||
string(10) "x.original"
|
||||
|
||||
Warning: Parameter 1 to C::__construct() expected to be a reference, value given in %sbug42976.php on line 18
|
||||
|
||||
Warning: ReflectionClass::newInstanceArgs(): Invocation of C's constructor failed in %sbug42976.php on line 18
|
||||
string(10) "x.original"
|
||||
Done
|
||||
|
@ -14,13 +14,13 @@ echo "Done\n";
|
||||
?>
|
||||
--EXPECTF--
|
||||
Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 5
|
||||
NULL
|
||||
bool(true)
|
||||
|
||||
Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 6
|
||||
NULL
|
||||
|
||||
Warning: Parameter 1 to sort() expected to be a reference, value given in %sbug41970.php on line 7
|
||||
NULL
|
||||
bool(true)
|
||||
|
||||
Warning: strlen() expects parameter 1 to be string, array given in %sbug41970.php on line 8
|
||||
NULL
|
||||
|
Loading…
Reference in New Issue
Block a user