|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
?? ??? 2020, PHP 7.4.11
+- Core:
+ . Fixed bug #79979 (passing value to by-ref param via CUFA crashes). (cmb,
+ Nikita)
+
- Calendar:
. Fixed bug #80007 (Potential type confusion in unixtojd() parameter parsing).
(Andy Postnikov)
--- /dev/null
+--TEST--
+Bug #79979 (passing value to by-ref param via CUF(A) crashes)
+--FILE--
+<?php
+call_user_func_array("str_replace", ["a", "b", "c", 0]);
+
+$cufa = "call_user_func_array";
+$cufa("str_replace", ["a", "b", "c", 0]);
+
+call_user_func_array($cufa, ["str_replace", ["a", "b", "c", 0]]);
+?>
+--EXPECTF--
+Warning: Parameter 4 to str_replace() expected to be a reference, value given in %s on line %d
+
+Warning: Parameter 4 to str_replace() expected to be a reference, value given in %s on line %d
+
+Warning: Parameter 4 to str_replace() expected to be a reference, value given in %s on line %d
for (i=0; i<fci->param_count; i++) {
zval *param;
zval *arg = &fci->params[i];
+ zend_bool must_wrap = 0;
if (ARG_SHOULD_BE_SENT_BY_REF(func, i + 1)) {
if (UNEXPECTED(!Z_ISREF_P(arg))) {
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. */
+ * and perform the call with the value wrapped in a reference. */
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));
+ must_wrap = 1;
if (UNEXPECTED(EG(exception))) {
ZEND_CALL_NUM_ARGS(call) = i;
zend_vm_stack_free_args(call);
}
param = ZEND_CALL_ARG(call, i+1);
- ZVAL_COPY(param, arg);
+ if (EXPECTED(!must_wrap)) {
+ ZVAL_COPY(param, arg);
+ } else {
+ ZVAL_NEW_REF(param, arg);
+ }
}
if (UNEXPECTED(func->op_array.fn_flags & ZEND_ACC_CLOSURE)) {
arg_num = 1;
param = ZEND_CALL_ARG(EX(call), 1);
ZEND_HASH_FOREACH_VAL(ht, arg) {
+ zend_bool must_wrap = 0;
if (skip > 0) {
skip--;
continue;
/* By-value send is not allowed -- emit a warning,
* but still perform the call. */
zend_param_must_be_ref(EX(call)->func, arg_num);
+ must_wrap = 1;
}
}
} else {
arg = Z_REFVAL_P(arg);
}
}
- ZVAL_COPY(param, arg);
+ if (EXPECTED(!must_wrap)) {
+ ZVAL_COPY(param, arg);
+ } else {
+ ZVAL_NEW_REF(param, arg);
+ }
ZEND_CALL_NUM_ARGS(EX(call))++;
arg_num++;
param++;
arg_num = 1;
param = ZEND_CALL_ARG(EX(call), 1);
ZEND_HASH_FOREACH_VAL(ht, arg) {
+ zend_bool must_wrap = 0;
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)) {
/* By-value send is not allowed -- emit a warning,
* but still perform the call. */
zend_param_must_be_ref(EX(call)->func, arg_num);
+ must_wrap = 1;
}
}
} else {
arg = Z_REFVAL_P(arg);
}
}
- ZVAL_COPY(param, arg);
+ if (EXPECTED(!must_wrap)) {
+ ZVAL_COPY(param, arg);
+ } else {
+ ZVAL_NEW_REF(param, arg);
+ }
ZEND_CALL_NUM_ARGS(EX(call))++;
arg_num++;
param++;
arg_num = 1;
param = ZEND_CALL_ARG(EX(call), 1);
ZEND_HASH_FOREACH_VAL(ht, arg) {
+ zend_bool must_wrap = 0;
if (skip > 0) {
skip--;
continue;
/* By-value send is not allowed -- emit a warning,
* but still perform the call. */
zend_param_must_be_ref(EX(call)->func, arg_num);
+ must_wrap = 1;
}
}
} else {
arg = Z_REFVAL_P(arg);
}
}
- ZVAL_COPY(param, arg);
+ if (EXPECTED(!must_wrap)) {
+ ZVAL_COPY(param, arg);
+ } else {
+ ZVAL_NEW_REF(param, arg);
+ }
ZEND_CALL_NUM_ARGS(EX(call))++;
arg_num++;
param++;
arg_num = 1;
param = ZEND_CALL_ARG(EX(call), 1);
ZEND_HASH_FOREACH_VAL(ht, arg) {
+ zend_bool must_wrap = 0;
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)) {
/* By-value send is not allowed -- emit a warning,
* but still perform the call. */
zend_param_must_be_ref(EX(call)->func, arg_num);
+ must_wrap = 1;
}
}
} else {
arg = Z_REFVAL_P(arg);
}
}
- ZVAL_COPY(param, arg);
+ if (EXPECTED(!must_wrap)) {
+ ZVAL_COPY(param, arg);
+ } else {
+ ZVAL_NEW_REF(param, arg);
+ }
ZEND_CALL_NUM_ARGS(EX(call))++;
arg_num++;
param++;