diff --git a/Zend/tests/bug61273.phpt b/Zend/tests/bug61273.phpt index aee35c6f4f5ee..9430ab65b2692 100644 --- a/Zend/tests/bug61273.phpt +++ b/Zend/tests/bug61273.phpt @@ -8,7 +8,7 @@ Bug #61273 (call_user_func_array with more than 16333 arguments leaks / crashes) * we should trick EG(argument_stack) into growing */ $args = array_fill(0, 64 * 1024 - 64, 0); -call_user_func_array(function(&$a) {}, $args); +call_user_func_array(function(&$a) {}, (array)$args); echo strval("okey"); --EXPECTF-- Warning: Parameter 1 to {closure}() expected to be a reference, value given in %sbug61273.php on line %d diff --git a/Zend/tests/bug72101.phpt b/Zend/tests/bug72101.phpt index a04425cee4056..d94f53eccab07 100644 --- a/Zend/tests/bug72101.phpt +++ b/Zend/tests/bug72101.phpt @@ -8,7 +8,7 @@ class PHPUnit_Framework_MockObject_Stub_ReturnCallback { $this->callback = $callback; } public function invoke($invocation) { - return call_user_func_array($this->callback, $invocation->parameters); + return call_user_func_array($this->callback, (array)$invocation->parameters); } } diff --git a/Zend/tests/call_user_func_array_prefer_ref.phpt b/Zend/tests/call_user_func_array_prefer_ref.phpt index d7a5fd913a112..49c52c8e92e2d 100644 --- a/Zend/tests/call_user_func_array_prefer_ref.phpt +++ b/Zend/tests/call_user_func_array_prefer_ref.phpt @@ -37,11 +37,11 @@ array(1) { [0]=> array(3) { [0]=> - int(3) + int(1) [1]=> int(2) [2]=> - int(1) + int(3) } } array(3) { @@ -56,11 +56,11 @@ array(1) { [0]=> array(3) { [0]=> - int(3) + int(1) [1]=> int(2) [2]=> - int(1) + int(3) } } array(3) { diff --git a/Zend/zend_API.c b/Zend/zend_API.c index fb0194f4af594..db7612b73a8ea 100644 --- a/Zend/zend_API.c +++ b/Zend/zend_API.c @@ -3485,10 +3485,9 @@ ZEND_API int zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(args), arg) { if (func && !Z_ISREF_P(arg) && ARG_SHOULD_BE_SENT_BY_REF(func, n)) { - ZVAL_NEW_REF(params, arg); - if (Z_REFCOUNTED_P(arg)) { - Z_ADDREF_P(arg); - } + ZVAL_NEW_REF(arg, arg); + Z_ADDREF_P(arg); + ZVAL_REF(params, Z_REF_P(arg)); } else { ZVAL_COPY(params, arg); } diff --git a/Zend/zend_compile.c b/Zend/zend_compile.c index fc77c6ad2f802..440a4d5e3c2b6 100644 --- a/Zend/zend_compile.c +++ b/Zend/zend_compile.c @@ -3519,7 +3519,11 @@ int zend_compile_func_cufa(znode *result, zend_ast_list *args, zend_string *lcna } zend_compile_init_user_func(args->child[0], 0, lcname); - zend_compile_expr(&arg_node, args->child[1]); + if (zend_is_variable(args->child[1]) && !zend_is_call(args->child[1])) { + zend_compile_var(&arg_node, args->child[1], BP_VAR_W); + } else { + zend_compile_expr(&arg_node, args->child[1]); + } zend_emit_op(NULL, ZEND_SEND_ARRAY, &arg_node, NULL); zend_emit_op(result, ZEND_DO_FCALL, NULL, NULL); diff --git a/Zend/zend_vm_def.h b/Zend/zend_vm_def.h index 2498b79f39a32..4d0dea9ac1d8c 100644 --- a/Zend/zend_vm_def.h +++ b/Zend/zend_vm_def.h @@ -4585,14 +4585,18 @@ ZEND_VM_C_LABEL(send_again): ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY) +ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, CONST|TMP|VAR|CV, ANY) { USE_OPLINE zend_free_op free_op1; zval *args; SAVE_OPLINE(); - args = GET_OP1_ZVAL_PTR(BP_VAR_R); + if (OP1_TYPE & (IS_VAR|IS_CV)) { + args = GET_OP1_ZVAL_PTR_PTR(BP_VAR_R); + } else { + args = GET_OP1_ZVAL_PTR(BP_VAR_R); + } if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { @@ -4617,6 +4621,20 @@ ZEND_VM_HANDLER(119, ZEND_SEND_ARRAY, ANY, ANY) zval *arg, *param; ZEND_VM_C_LABEL(send_array): + if ((OP1_TYPE & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) { + ht = Z_ARRVAL_P(args); + arg_num = 1; + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + SEPARATE_ARRAY(args); + break; + } + } + arg_num++; + } ZEND_HASH_FOREACH_END(); + } + ht = Z_ARRVAL_P(args); zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); @@ -4625,7 +4643,9 @@ ZEND_VM_C_LABEL(send_array): ZEND_HASH_FOREACH_VAL(ht, arg) { 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)) { + if (OP1_TYPE & (IS_VAR|IS_CV)) { + ZVAL_NEW_REF(arg, arg); + } else 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", arg_num, @@ -4658,7 +4678,11 @@ ZEND_VM_C_LABEL(send_array): param++; } ZEND_HASH_FOREACH_END(); } - FREE_OP1(); + if (OP1_TYPE & (IS_VAR|IS_CV)) { + FREE_OP1_VAR_PTR(); + } else { + FREE_OP1(); + } ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } diff --git a/Zend/zend_vm_execute.h b/Zend/zend_vm_execute.h index b9ce818b9708d..ce3a3b2aff2a3 100644 --- a/Zend/zend_vm_execute.h +++ b/Zend/zend_vm_execute.h @@ -1382,83 +1382,6 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_UNPACK_SPEC_HANDLER(ZEND_ ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); } -static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) -{ - USE_OPLINE - zend_free_op free_op1; - zval *args; - - SAVE_OPLINE(); - args = get_zval_ptr(opline->op1_type, opline->op1, execute_data, &free_op1, BP_VAR_R); - - if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { - if ((opline->op1_type & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { - args = Z_REFVAL_P(args); - if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { - goto send_array; - } - } - zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); - 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); - } else { - uint32_t arg_num; - HashTable *ht; - zval *arg, *param; - -send_array: - ht = Z_ARRVAL_P(args); - zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); - - arg_num = 1; - param = ZEND_CALL_ARG(EX(call), 1); - ZEND_HASH_FOREACH_VAL(ht, arg) { - 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", - 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 { - if (Z_ISREF_P(arg) && - !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { - /* don't separate references for __call */ - arg = Z_REFVAL_P(arg); - } - } - ZVAL_COPY(param, arg); - ZEND_CALL_NUM_ARGS(EX(call))++; - arg_num++; - param++; - } ZEND_HASH_FOREACH_END(); - } - FREE_OP(free_op1); - ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); -} - static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_RECV_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -3116,6 +3039,107 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_CONST_QUICK_H ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *args; + + SAVE_OPLINE(); + if (IS_CONST & (IS_VAR|IS_CV)) { + args = NULL; + } else { + args = EX_CONSTANT(opline->op1); + } + + if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { + if ((IS_CONST & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { + args = Z_REFVAL_P(args); + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + goto send_array; + } + } + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + 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); + } else { + uint32_t arg_num; + HashTable *ht; + zval *arg, *param; + +send_array: + if ((IS_CONST & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) { + ht = Z_ARRVAL_P(args); + arg_num = 1; + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + SEPARATE_ARRAY(args); + break; + } + } + arg_num++; + } ZEND_HASH_FOREACH_END(); + } + + ht = Z_ARRVAL_P(args); + zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); + + arg_num = 1; + param = ZEND_CALL_ARG(EX(call), 1); + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (IS_CONST & (IS_VAR|IS_CV)) { + ZVAL_NEW_REF(arg, arg); + } else 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", + 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 { + if (Z_ISREF_P(arg) && + !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + } + ZVAL_COPY(param, arg); + ZEND_CALL_NUM_ARGS(EX(call))++; + arg_num++; + param++; + } ZEND_HASH_FOREACH_END(); + } + if (IS_CONST & (IS_VAR|IS_CV)) { + + } else { + + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_BOOL_SPEC_CONST_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -12412,6 +12436,107 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAL_EX_SPEC_TMP_QUICK_HAN ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + + SAVE_OPLINE(); + if (IS_TMP_VAR & (IS_VAR|IS_CV)) { + args = NULL; + } else { + args = _get_zval_ptr_tmp(opline->op1.var, execute_data, &free_op1); + } + + if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { + if ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { + args = Z_REFVAL_P(args); + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + goto send_array; + } + } + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + 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); + } else { + uint32_t arg_num; + HashTable *ht; + zval *arg, *param; + +send_array: + if ((IS_TMP_VAR & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) { + ht = Z_ARRVAL_P(args); + arg_num = 1; + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + SEPARATE_ARRAY(args); + break; + } + } + arg_num++; + } ZEND_HASH_FOREACH_END(); + } + + ht = Z_ARRVAL_P(args); + zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); + + arg_num = 1; + param = ZEND_CALL_ARG(EX(call), 1); + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (IS_TMP_VAR & (IS_VAR|IS_CV)) { + ZVAL_NEW_REF(arg, arg); + } else 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", + 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 { + if (Z_ISREF_P(arg) && + !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + } + ZVAL_COPY(param, arg); + ZEND_CALL_NUM_ARGS(EX(call))++; + arg_num++; + param++; + } ZEND_HASH_FOREACH_END(); + } + if (IS_TMP_VAR & (IS_VAR|IS_CV)) { + + } else { + zval_ptr_dtor_nogc(free_op1); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_CAST_SPEC_TMP_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -15879,6 +16004,107 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_VAR_QUICK_HAN ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + zend_free_op free_op1; + zval *args; + + SAVE_OPLINE(); + if (IS_VAR & (IS_VAR|IS_CV)) { + args = _get_zval_ptr_ptr_var(opline->op1.var, execute_data, &free_op1); + } else { + args = _get_zval_ptr_var(opline->op1.var, execute_data, &free_op1); + } + + if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { + if ((IS_VAR & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { + args = Z_REFVAL_P(args); + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + goto send_array; + } + } + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + 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); + } else { + uint32_t arg_num; + HashTable *ht; + zval *arg, *param; + +send_array: + if ((IS_VAR & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) { + ht = Z_ARRVAL_P(args); + arg_num = 1; + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + SEPARATE_ARRAY(args); + break; + } + } + arg_num++; + } ZEND_HASH_FOREACH_END(); + } + + ht = Z_ARRVAL_P(args); + zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); + + arg_num = 1; + param = ZEND_CALL_ARG(EX(call), 1); + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (IS_VAR & (IS_VAR|IS_CV)) { + ZVAL_NEW_REF(arg, arg); + } else 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", + 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 { + if (Z_ISREF_P(arg) && + !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + } + ZVAL_COPY(param, arg); + ZEND_CALL_NUM_ARGS(EX(call))++; + arg_num++; + param++; + } ZEND_HASH_FOREACH_END(); + } + if (IS_VAR & (IS_VAR|IS_CV)) { + if (UNEXPECTED(free_op1)) {zval_ptr_dtor_nogc(free_op1);}; + } else { + zval_ptr_dtor_nogc(free_op1); + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_VAR_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -34893,6 +35119,107 @@ static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_VAR_EX_SPEC_CV_QUICK_HAND ZEND_VM_NEXT_OPCODE(); } +static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_ARRAY_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) +{ + USE_OPLINE + + zval *args; + + SAVE_OPLINE(); + if (IS_CV & (IS_VAR|IS_CV)) { + args = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); + } else { + args = _get_zval_ptr_cv_BP_VAR_R(execute_data, opline->op1.var); + } + + if (UNEXPECTED(Z_TYPE_P(args) != IS_ARRAY)) { + if ((IS_CV & (IS_VAR|IS_CV)) && Z_ISREF_P(args)) { + args = Z_REFVAL_P(args); + if (EXPECTED(Z_TYPE_P(args) == IS_ARRAY)) { + goto send_array; + } + } + zend_internal_type_error(EX_USES_STRICT_TYPES(), "call_user_func_array() expects parameter 2 to be array, %s given", zend_get_type_by_const(Z_TYPE_P(args))); + 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); + } else { + uint32_t arg_num; + HashTable *ht; + zval *arg, *param; + +send_array: + if ((IS_CV & (IS_VAR|IS_CV)) && Z_REFCOUNT_P(args) > 1) { + ht = Z_ARRVAL_P(args); + arg_num = 1; + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + SEPARATE_ARRAY(args); + break; + } + } + arg_num++; + } ZEND_HASH_FOREACH_END(); + } + + ht = Z_ARRVAL_P(args); + zend_vm_stack_extend_call_frame(&EX(call), 0, zend_hash_num_elements(ht)); + + arg_num = 1; + param = ZEND_CALL_ARG(EX(call), 1); + ZEND_HASH_FOREACH_VAL(ht, arg) { + if (ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { + if (UNEXPECTED(!Z_ISREF_P(arg))) { + if (IS_CV & (IS_VAR|IS_CV)) { + ZVAL_NEW_REF(arg, arg); + } else 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", + 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 { + if (Z_ISREF_P(arg) && + !(EX(call)->func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) { + /* don't separate references for __call */ + arg = Z_REFVAL_P(arg); + } + } + ZVAL_COPY(param, arg); + ZEND_CALL_NUM_ARGS(EX(call))++; + arg_num++; + param++; + } ZEND_HASH_FOREACH_END(); + } + if (IS_CV & (IS_VAR|IS_CV)) { + + } else { + + } + ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); +} + static ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_SEND_USER_SPEC_CV_HANDLER(ZEND_OPCODE_HANDLER_ARGS) { USE_OPLINE @@ -59577,7 +59904,11 @@ void zend_init_opcodes_handlers(void) ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, - ZEND_SEND_ARRAY_SPEC_HANDLER, + ZEND_SEND_ARRAY_SPEC_CONST_HANDLER, + ZEND_SEND_ARRAY_SPEC_TMP_HANDLER, + ZEND_SEND_ARRAY_SPEC_VAR_HANDLER, + ZEND_NULL_HANDLER, + ZEND_SEND_ARRAY_SPEC_CV_HANDLER, ZEND_NULL_HANDLER, ZEND_NULL_HANDLER, ZEND_SEND_USER_SPEC_VAR_HANDLER, @@ -61749,7 +62080,7 @@ void zend_init_opcodes_handlers(void) 2257 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2282 | SPEC_RULE_OP1 | SPEC_RULE_OP2, 2307 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4596, + 4600, 2332, 2333, 2334, @@ -61768,75 +62099,75 @@ void zend_init_opcodes_handlers(void) 2487 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG, 2497 | SPEC_RULE_OP1, 2502 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2527, - 2528 | SPEC_RULE_OP1, - 2533 | SPEC_RULE_OP1, - 2538 | SPEC_RULE_OP1, - 2543 | SPEC_RULE_OP1, - 2548 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2573 | SPEC_RULE_OP1, - 2578 | SPEC_RULE_OP1, - 2583 | SPEC_RULE_OP1, - 2588 | SPEC_RULE_OP2, - 2593 | SPEC_RULE_RETVAL, - 2595 | SPEC_RULE_RETVAL, + 2527 | SPEC_RULE_OP1, + 2532 | SPEC_RULE_OP1, + 2537 | SPEC_RULE_OP1, + 2542 | SPEC_RULE_OP1, + 2547 | SPEC_RULE_OP1, + 2552 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2577 | SPEC_RULE_OP1, + 2582 | SPEC_RULE_OP1, + 2587 | SPEC_RULE_OP1, + 2592 | SPEC_RULE_OP2, 2597 | SPEC_RULE_RETVAL, - 2599 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2624 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2649 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2674 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2699 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA, - 2824, - 2825 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2850, - 2851 | SPEC_RULE_OP2, - 2856, - 2857 | SPEC_RULE_OP1, - 2862 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 2887 | SPEC_RULE_OP2, - 2892 | SPEC_RULE_OP2, - 2897, - 2898 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA, - 3023 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3048, - 3049, - 3050, - 3051 | SPEC_RULE_OP1, - 3056 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3081, - 3082, - 3083 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3108, - 3109, - 3110, - 3111 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3136 | SPEC_RULE_OP1, - 3141, - 3142, - 3143, - 3144, - 3145 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3170 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_DIM_OBJ, - 3245 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3270 | SPEC_RULE_OP1, - 3275 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3300, - 3301 | SPEC_RULE_OP2, - 3306 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3331 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3356 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3381 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3406 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3431 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3456 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3481 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3506 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3531 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3556 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 3581 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4596, - 3606 | SPEC_RULE_OP1 | SPEC_RULE_OP2, - 4596 + 2599 | SPEC_RULE_RETVAL, + 2601 | SPEC_RULE_RETVAL, + 2603 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2628 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2653 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2678 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2703 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA, + 2828, + 2829 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2854, + 2855 | SPEC_RULE_OP2, + 2860, + 2861 | SPEC_RULE_OP1, + 2866 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 2891 | SPEC_RULE_OP2, + 2896 | SPEC_RULE_OP2, + 2901, + 2902 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_OP_DATA, + 3027 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3052, + 3053, + 3054, + 3055 | SPEC_RULE_OP1, + 3060 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3085, + 3086, + 3087 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3112, + 3113, + 3114, + 3115 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3140 | SPEC_RULE_OP1, + 3145, + 3146, + 3147, + 3148, + 3149 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3174 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_DIM_OBJ, + 3249 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3274 | SPEC_RULE_OP1, + 3279 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3304, + 3305 | SPEC_RULE_OP2, + 3310 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3335 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3360 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3385 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3410 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3435 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3460 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3485 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3510 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3535 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3560 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 3585 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4600, + 3610 | SPEC_RULE_OP1 | SPEC_RULE_OP2, + 4600 }; zend_opcode_handlers = labels; zend_handlers_count = sizeof(labels) / sizeof(void*); @@ -61943,7 +62274,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3631 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3635 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -61951,7 +62282,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3656 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3660 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -61959,7 +62290,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3681 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3685 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -61970,17 +62301,17 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3706 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3710 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if ((op1_info == MAY_BE_LONG && op2_info == MAY_BE_LONG)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3731 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3735 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3756 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3760 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_MUL: @@ -61988,7 +62319,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3781 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3785 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -61996,7 +62327,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3806 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3810 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62004,7 +62335,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3831 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 3835 | SPEC_RULE_OP1 | SPEC_RULE_OP2; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62015,7 +62346,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3856 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3860 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62023,7 +62354,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 3931 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 3935 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62034,7 +62365,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4006 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4010 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62042,7 +62373,7 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4081 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4085 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; if (op->op1_type > op->op2_type) { zend_swap_operands(op); } @@ -62053,12 +62384,12 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4156 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4160 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4231 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4235 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_IS_SMALLER_OR_EQUAL: @@ -62066,70 +62397,70 @@ ZEND_API void zend_vm_set_opcode_handler_ex(zend_op* op, uint32_t op1_info, uint if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4306 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4310 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } else if ((op1_info == MAY_BE_DOUBLE && op2_info == MAY_BE_DOUBLE)) { if (op->op1_type == IS_CONST && op->op2_type == IS_CONST) { break; } - spec = 4381 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; + spec = 4385 | SPEC_RULE_OP1 | SPEC_RULE_OP2 | SPEC_RULE_SMART_BRANCH; } break; case ZEND_QM_ASSIGN: if ((op1_info == MAY_BE_DOUBLE)) { - spec = 4546 | SPEC_RULE_OP1; + spec = 4550 | SPEC_RULE_OP1; } else if ((!(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE))))) { - spec = 4551 | SPEC_RULE_OP1; + spec = 4555 | SPEC_RULE_OP1; } break; case ZEND_PRE_INC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4456 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4460 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4466 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4470 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4476 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4480 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_PRE_DEC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4486 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4490 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4496 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4500 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4506 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; + spec = 4510 | SPEC_RULE_OP1 | SPEC_RULE_RETVAL; } break; case ZEND_POST_INC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4516 | SPEC_RULE_OP1; + spec = 4520 | SPEC_RULE_OP1; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4521 | SPEC_RULE_OP1; + spec = 4525 | SPEC_RULE_OP1; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4526 | SPEC_RULE_OP1; + spec = 4530 | SPEC_RULE_OP1; } break; case ZEND_POST_DEC: if ((res_info == MAY_BE_LONG && op1_info == MAY_BE_LONG)) { - spec = 4531 | SPEC_RULE_OP1; + spec = 4535 | SPEC_RULE_OP1; } else if ((op1_info == MAY_BE_LONG)) { - spec = 4536 | SPEC_RULE_OP1; + spec = 4540 | SPEC_RULE_OP1; } else if ((op1_info == (MAY_BE_LONG|MAY_BE_DOUBLE))) { - spec = 4541 | SPEC_RULE_OP1; + spec = 4545 | SPEC_RULE_OP1; } break; case ZEND_SEND_VAR_EX: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4586 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; + spec = 4590 | SPEC_RULE_OP1 | SPEC_RULE_QUICK_ARG; } break; case ZEND_FETCH_DIM_R: if ((!(op2_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { - spec = 4556 | SPEC_RULE_OP1 | SPEC_RULE_OP2; + spec = 4560 | SPEC_RULE_OP1 | SPEC_RULE_OP2; } break; case ZEND_SEND_VAR: if ((op1_info & (MAY_BE_UNDEF|MAY_BE_REF)) == 0) { - spec = 4581 | SPEC_RULE_OP1; + spec = 4585 | SPEC_RULE_OP1; } break; default: diff --git a/Zend/zend_vm_opcodes.c b/Zend/zend_vm_opcodes.c index 11e9b1368bc4d..8c2459d82fb6a 100644 --- a/Zend/zend_vm_opcodes.c +++ b/Zend/zend_vm_opcodes.c @@ -331,7 +331,7 @@ static uint32_t zend_vm_opcodes_flags[187] = { 0x00001003, 0x00001001, 0x01000703, - 0x00000000, + 0x00000003, 0x00001001, 0x00000007, 0x00000003, diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index 45024c11b7111..2b9e02f7cf696 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -738,9 +738,9 @@ static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */ fci->retval = &stmt->fetch.cls.retval; fci->param_count = 0; fci->params = NULL; - fci->no_separation = 1; + fci->no_separation = 0; - zend_fcall_info_args_ex(fci, ce->constructor, &stmt->fetch.cls.ctor_args); + zend_fcall_info_args_ex(fci, NULL, &stmt->fetch.cls.ctor_args); fcc->initialized = 1; fcc->function_handler = ce->constructor; diff --git a/ext/standard/basic_functions.c b/ext/standard/basic_functions.c index ef628cc6cba06..c2c4ef6311770 100644 --- a/ext/standard/basic_functions.c +++ b/ext/standard/basic_functions.c @@ -700,7 +700,7 @@ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_call_user_func_array, 0, 0, 2) ZEND_ARG_INFO(0, function_name) - ZEND_ARG_INFO(0, parameters) /* ARRAY_INFO(0, parameters, 1) */ + ZEND_ARG_INFO(ZEND_SEND_PREFER_REF, parameters) /* ARRAY_INFO(0, parameters, 1) */ ZEND_END_ARG_INFO() ZEND_BEGIN_ARG_INFO_EX(arginfo_forward_static_call, 0, 0, 1) @@ -4831,6 +4831,7 @@ PHP_FUNCTION(call_user_func_array) zval *params, retval; zend_fcall_info fci; zend_fcall_info_cache fci_cache; + zend_function *func; #ifndef FAST_ZPP if (zend_parse_parameters(ZEND_NUM_ARGS(), "fa/", &fci, &fci_cache, ¶ms) == FAILURE) { @@ -4843,7 +4844,11 @@ PHP_FUNCTION(call_user_func_array) ZEND_PARSE_PARAMETERS_END(); #endif - zend_fcall_info_args(&fci, params); + func = NULL; + if (Z_ISREF_P(ZEND_CALL_ARG(execute_data, 2)) && fci_cache.initialized) { + func = fci_cache.function_handler; + } + zend_fcall_info_args_ex(&fci, func, params); fci.retval = &retval; if (zend_call_function(&fci, &fci_cache) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) { diff --git a/ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt b/ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt index c05a329342436..790fe66b566a4 100644 --- a/ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt +++ b/ext/standard/tests/general_functions/call_user_func_array_variation_001.phpt @@ -16,7 +16,12 @@ $arg = array('original'); call_user_func_array('by_val', $arg); var_dump($arg); -echo "------ Calling by_ref() with unreferenced argument ------\n"; +echo "------ Calling by_ref() with unreferenced argument (warning) ------\n"; +$arg = array('original'); +call_user_func_array('by_ref', (array)$arg); +var_dump($arg); + +echo "------ Calling by_ref() with unreferenced argument (convert to ref) ------\n"; $arg = array('original'); call_user_func_array('by_ref', $arg); var_dump($arg); @@ -40,13 +45,18 @@ array(1) { [0]=> string(8) "original" } ------- Calling by_ref() with unreferenced argument ------ +------ Calling by_ref() with unreferenced argument (warning) ------ Warning: Parameter 1 to by_ref() expected to be a reference, value given in %s on line %d array(1) { [0]=> string(8) "original" } +------ Calling by_ref() with unreferenced argument (convert to ref) ------ +array(1) { + [0]=> + string(7) "changed" +} ------ Calling by_val() with referenced argument ------ array(1) { [0]=>